From fbfc1722e5c779f907e5f2ceda529a39813b7255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Thu, 12 Feb 2026 00:28:41 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20Update=20source=20examples=20and?= =?UTF-8?q?=20docs=20from=20Python=203.9=20to=203.10?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/advanced/additional-responses.md | 4 +- .../en/docs/advanced/advanced-dependencies.md | 8 +- docs/en/docs/advanced/async-tests.md | 8 +- docs/en/docs/advanced/behind-a-proxy.md | 12 +- docs/en/docs/advanced/custom-response.md | 32 ++-- docs/en/docs/advanced/events.md | 12 +- docs/en/docs/advanced/generate-clients.md | 8 +- docs/en/docs/advanced/middleware.md | 6 +- docs/en/docs/advanced/openapi-webhooks.md | 2 +- .../path-operation-advanced-configuration.md | 14 +- .../advanced/response-change-status-code.md | 2 +- docs/en/docs/advanced/response-cookies.md | 4 +- docs/en/docs/advanced/response-directly.md | 2 +- docs/en/docs/advanced/response-headers.md | 4 +- .../docs/advanced/security/http-basic-auth.md | 6 +- docs/en/docs/advanced/settings.md | 20 +- docs/en/docs/advanced/sub-applications.md | 6 +- docs/en/docs/advanced/templates.md | 2 +- docs/en/docs/advanced/testing-events.md | 4 +- docs/en/docs/advanced/testing-websockets.md | 2 +- .../docs/advanced/using-request-directly.md | 2 +- docs/en/docs/advanced/websockets.md | 8 +- docs/en/docs/advanced/wsgi.md | 2 +- .../authentication-error-status-code.md | 2 +- docs/en/docs/how-to/conditional-openapi.md | 2 +- docs/en/docs/how-to/configure-swagger-ui.md | 6 +- docs/en/docs/how-to/custom-docs-ui-assets.md | 14 +- docs/en/docs/how-to/extending-openapi.md | 10 +- docs/en/docs/how-to/graphql.md | 2 +- docs/en/docs/python-types.md | 24 +-- docs/en/docs/tutorial/background-tasks.md | 6 +- docs/en/docs/tutorial/bigger-applications.md | 26 +-- docs/en/docs/tutorial/body-nested-models.md | 4 +- docs/en/docs/tutorial/cors.md | 2 +- docs/en/docs/tutorial/debugging.md | 2 +- ...pendencies-in-path-operation-decorators.md | 8 +- .../dependencies/dependencies-with-yield.md | 22 +-- .../dependencies/global-dependencies.md | 2 +- docs/en/docs/tutorial/extra-models.md | 4 +- docs/en/docs/tutorial/first-steps.md | 14 +- docs/en/docs/tutorial/handling-errors.md | 16 +- docs/en/docs/tutorial/metadata.md | 12 +- docs/en/docs/tutorial/middleware.md | 4 +- .../tutorial/path-operation-configuration.md | 4 +- .../path-params-numeric-validations.md | 14 +- docs/en/docs/tutorial/path-params.md | 20 +- .../tutorial/query-params-str-validations.md | 8 +- docs/en/docs/tutorial/query-params.md | 4 +- docs/en/docs/tutorial/request-files.md | 12 +- docs/en/docs/tutorial/request-form-models.md | 4 +- .../docs/tutorial/request-forms-and-files.md | 4 +- docs/en/docs/tutorial/request-forms.md | 4 +- docs/en/docs/tutorial/response-model.md | 4 +- docs/en/docs/tutorial/response-status-code.md | 6 +- docs/en/docs/tutorial/security/first-steps.md | 6 +- .../tutorial/security/get-current-user.md | 2 +- docs/en/docs/tutorial/static-files.md | 2 +- docs/en/docs/tutorial/testing.md | 6 +- .../additional_responses/tutorial001_py310.py | 22 +++ .../additional_responses/tutorial002_py39.py | 30 --- .../additional_responses/tutorial003_py310.py | 37 ++++ .../additional_responses/tutorial004_py39.py | 32 ---- .../tutorial001_an_py39.py | 25 --- .../tutorial001_py39.py | 25 --- .../advanced_middleware/tutorial001_py310.py | 11 ++ .../advanced_middleware/tutorial002_py310.py | 13 ++ .../advanced_middleware/tutorial003_py310.py | 11 ++ docs_src/app_testing/app_a_py310/__init__.py | 0 docs_src/app_testing/app_a_py310/main.py | 8 + docs_src/app_testing/app_a_py310/test_main.py | 11 ++ docs_src/app_testing/app_b_an_py39/main.py | 38 ---- .../app_testing/app_b_an_py39/test_main.py | 65 ------- docs_src/app_testing/app_b_py39/main.py | 38 ---- docs_src/app_testing/app_b_py39/test_main.py | 65 ------- docs_src/app_testing/tutorial001_py310.py | 18 ++ docs_src/app_testing/tutorial002_py310.py | 31 +++ docs_src/app_testing/tutorial003_py310.py | 24 +++ docs_src/app_testing/tutorial004_py310.py | 43 +++++ docs_src/async_tests/app_a_py310/__init__.py | 0 docs_src/async_tests/app_a_py310/main.py | 8 + docs_src/async_tests/app_a_py310/test_main.py | 14 ++ .../tutorial001_an_py310.py | 21 ++ .../background_tasks/tutorial001_py310.py | 15 ++ .../background_tasks/tutorial002_an_py39.py | 26 --- docs_src/background_tasks/tutorial002_py39.py | 26 --- .../behind_a_proxy/tutorial001_01_py310.py | 8 + docs_src/behind_a_proxy/tutorial001_py310.py | 8 + docs_src/behind_a_proxy/tutorial002_py310.py | 8 + docs_src/behind_a_proxy/tutorial003_py310.py | 14 ++ docs_src/behind_a_proxy/tutorial004_py310.py | 15 ++ .../app_an_py310/__init__.py | 0 .../app_an_py310/dependencies.py | 13 ++ .../app_an_py310/internal/__init__.py | 0 .../internal/admin.py | 0 .../bigger_applications/app_an_py310/main.py | 23 +++ .../app_an_py310/routers/__init__.py | 0 .../routers/items.py | 0 .../routers/users.py | 0 .../bigger_applications/app_py310/__init__.py | 0 .../app_py310/dependencies.py | 11 ++ .../app_py310/internal/__init__.py | 0 .../bigger_applications/app_py310/main.py | 23 +++ .../app_py310/routers/__init__.py | 0 docs_src/body/tutorial001_py39.py | 19 -- docs_src/body/tutorial002_py39.py | 23 --- docs_src/body/tutorial003_py39.py | 19 -- docs_src/body/tutorial004_py39.py | 22 --- docs_src/body_fields/tutorial001_an_py39.py | 21 -- docs_src/body_fields/tutorial001_py39.py | 21 -- .../tutorial001_an_py39.py | 27 --- .../body_multiple_params/tutorial001_py39.py | 28 --- .../body_multiple_params/tutorial002_py39.py | 24 --- .../tutorial003_an_py39.py | 26 --- .../body_multiple_params/tutorial003_py39.py | 24 --- .../tutorial004_an_py39.py | 33 ---- .../body_multiple_params/tutorial004_py39.py | 33 ---- .../tutorial005_an_py39.py | 19 -- .../body_multiple_params/tutorial005_py39.py | 19 -- .../body_nested_models/tutorial001_py39.py | 20 -- .../body_nested_models/tutorial002_py39.py | 20 -- .../body_nested_models/tutorial003_py39.py | 20 -- .../body_nested_models/tutorial004_py39.py | 26 --- .../body_nested_models/tutorial005_py39.py | 26 --- .../body_nested_models/tutorial006_py39.py | 26 --- .../body_nested_models/tutorial007_py39.py | 32 ---- .../body_nested_models/tutorial008_py310.py | 14 ++ .../body_nested_models/tutorial009_py310.py | 8 + docs_src/body_updates/tutorial001_py39.py | 34 ---- docs_src/body_updates/tutorial002_py39.py | 37 ---- .../conditional_openapi/tutorial001_py310.py | 16 ++ .../configure_swagger_ui/tutorial001_py310.py | 8 + .../configure_swagger_ui/tutorial002_py310.py | 8 + .../configure_swagger_ui/tutorial003_py310.py | 8 + .../tutorial001_an_py39.py | 17 -- .../cookie_param_models/tutorial001_py39.py | 17 -- .../tutorial002_an_py39.py | 19 -- .../cookie_param_models/tutorial002_py39.py | 19 -- docs_src/cookie_params/tutorial001_an_py39.py | 10 - docs_src/cookie_params/tutorial001_py39.py | 10 - docs_src/cors/tutorial001_py310.py | 24 +++ docs_src/custom_docs_ui/tutorial001_py310.py | 38 ++++ docs_src/custom_docs_ui/tutorial002_py310.py | 41 ++++ .../tutorial001_an_py39.py | 35 ---- .../tutorial001_py39.py | 35 ---- .../tutorial002_an_py39.py | 29 --- .../tutorial002_py39.py | 29 --- .../tutorial003_py39.py | 39 ---- docs_src/custom_response/tutorial001_py310.py | 9 + .../custom_response/tutorial001b_py310.py | 9 + docs_src/custom_response/tutorial002_py310.py | 18 ++ docs_src/custom_response/tutorial003_py310.py | 19 ++ docs_src/custom_response/tutorial004_py310.py | 23 +++ docs_src/custom_response/tutorial005_py310.py | 9 + docs_src/custom_response/tutorial006_py310.py | 9 + .../custom_response/tutorial006b_py310.py | 9 + .../custom_response/tutorial006c_py310.py | 9 + docs_src/custom_response/tutorial007_py310.py | 14 ++ docs_src/custom_response/tutorial008_py310.py | 14 ++ docs_src/custom_response/tutorial009_py310.py | 10 + .../custom_response/tutorial009b_py310.py | 10 + .../custom_response/tutorial009c_py310.py | 19 ++ docs_src/custom_response/tutorial010_py310.py | 9 + docs_src/dataclasses_/tutorial001_py39.py | 20 -- docs_src/dataclasses_/tutorial002_py39.py | 26 --- docs_src/dataclasses_/tutorial003_py39.py | 55 ------ docs_src/debugging/tutorial001_py310.py | 15 ++ .../dependencies/tutorial001_02_an_py39.py | 24 --- docs_src/dependencies/tutorial001_an_py39.py | 21 -- docs_src/dependencies/tutorial001_py39.py | 21 -- docs_src/dependencies/tutorial002_an_py39.py | 25 --- docs_src/dependencies/tutorial002_py39.py | 25 --- docs_src/dependencies/tutorial003_an_py39.py | 25 --- docs_src/dependencies/tutorial003_py39.py | 25 --- docs_src/dependencies/tutorial004_an_py39.py | 25 --- docs_src/dependencies/tutorial004_py39.py | 25 --- docs_src/dependencies/tutorial005_an_py39.py | 25 --- docs_src/dependencies/tutorial005_py39.py | 23 --- docs_src/dependencies/tutorial006_an_py310.py | 21 ++ docs_src/dependencies/tutorial006_py310.py | 19 ++ docs_src/dependencies/tutorial007_py310.py | 6 + docs_src/dependencies/tutorial008_an_py310.py | 27 +++ docs_src/dependencies/tutorial008_py310.py | 25 +++ .../dependencies/tutorial008b_an_py310.py | 32 ++++ docs_src/dependencies/tutorial008b_py310.py | 30 +++ .../dependencies/tutorial008c_an_py310.py | 29 +++ docs_src/dependencies/tutorial008c_py310.py | 27 +++ .../dependencies/tutorial008d_an_py310.py | 30 +++ docs_src/dependencies/tutorial008d_py310.py | 28 +++ .../dependencies/tutorial008e_an_py310.py | 17 ++ docs_src/dependencies/tutorial008e_py310.py | 15 ++ docs_src/dependencies/tutorial010_py310.py | 14 ++ docs_src/dependencies/tutorial011_an_py310.py | 23 +++ docs_src/dependencies/tutorial011_py310.py | 21 ++ docs_src/dependencies/tutorial012_an_py310.py | 27 +++ docs_src/dependencies/tutorial012_py310.py | 25 +++ .../dependency_testing/tutorial001_an_py39.py | 59 ------ .../dependency_testing/tutorial001_py39.py | 59 ------ docs_src/encoder/tutorial001_py39.py | 23 --- docs_src/events/tutorial001_py310.py | 16 ++ docs_src/events/tutorial002_py310.py | 14 ++ docs_src/events/tutorial003_py310.py | 28 +++ .../extending_openapi/tutorial001_py310.py | 29 +++ .../extra_data_types/tutorial001_an_py39.py | 28 --- docs_src/extra_data_types/tutorial001_py39.py | 28 --- docs_src/extra_models/tutorial001_py39.py | 43 ----- docs_src/extra_models/tutorial002_py39.py | 41 ---- docs_src/extra_models/tutorial003_py39.py | 35 ---- docs_src/extra_models/tutorial004_py310.py | 20 ++ docs_src/extra_models/tutorial005_py310.py | 8 + docs_src/first_steps/tutorial001_py310.py | 8 + docs_src/first_steps/tutorial003_py310.py | 8 + .../generate_clients/tutorial001_py310.py | 26 +++ .../generate_clients/tutorial002_py310.py | 36 ++++ .../generate_clients/tutorial003_py310.py | 42 ++++ .../generate_clients/tutorial004_py310.py | 15 ++ docs_src/graphql_/tutorial001_py310.py | 25 +++ docs_src/handling_errors/tutorial001_py310.py | 12 ++ docs_src/handling_errors/tutorial002_py310.py | 16 ++ docs_src/handling_errors/tutorial003_py310.py | 25 +++ docs_src/handling_errors/tutorial004_py310.py | 26 +++ docs_src/handling_errors/tutorial005_py310.py | 25 +++ docs_src/handling_errors/tutorial006_py310.py | 28 +++ .../tutorial001_an_py39.py | 19 -- .../header_param_models/tutorial001_py39.py | 19 -- .../tutorial002_an_py39.py | 21 -- .../header_param_models/tutorial002_py39.py | 21 -- .../tutorial003_an_py39.py | 21 -- .../header_param_models/tutorial003_py39.py | 19 -- docs_src/header_params/tutorial001_an_py39.py | 10 - docs_src/header_params/tutorial001_py39.py | 10 - docs_src/header_params/tutorial002_an_py39.py | 14 -- docs_src/header_params/tutorial002_py39.py | 12 -- docs_src/header_params/tutorial003_an_py39.py | 10 - docs_src/header_params/tutorial003_py39.py | 10 - docs_src/metadata/tutorial001_1_py310.py | 38 ++++ docs_src/metadata/tutorial001_py310.py | 38 ++++ docs_src/metadata/tutorial002_py310.py | 8 + docs_src/metadata/tutorial003_py310.py | 8 + docs_src/metadata/tutorial004_py310.py | 28 +++ docs_src/middleware/tutorial001_py310.py | 14 ++ .../openapi_callbacks/tutorial001_py39.py | 53 ------ .../openapi_webhooks/tutorial001_py310.py | 25 +++ .../tutorial001_py310.py | 8 + .../tutorial002_py310.py | 24 +++ .../tutorial003_py310.py | 8 + .../tutorial004_py39.py | 30 --- .../tutorial005_py310.py | 8 + .../tutorial006_py310.py | 41 ++++ ...al007_pv1_py39.py => tutorial007_py310.py} | 8 +- .../tutorial001_py39.py | 19 -- .../tutorial002_py39.py | 29 --- .../tutorial002b_py310.py | 20 ++ .../tutorial003_py39.py | 23 --- .../tutorial004_py39.py | 28 --- .../tutorial005_py39.py | 32 ---- .../tutorial006_py310.py | 18 ++ docs_src/path_params/tutorial001_py310.py | 8 + docs_src/path_params/tutorial002_py310.py | 8 + docs_src/path_params/tutorial003_py310.py | 13 ++ docs_src/path_params/tutorial003b_py310.py | 13 ++ docs_src/path_params/tutorial004_py310.py | 8 + docs_src/path_params/tutorial005_py310.py | 23 +++ .../tutorial002_an_py310.py | 15 ++ .../tutorial002_py310.py | 11 ++ .../tutorial003_an_py310.py | 15 ++ .../tutorial003_py310.py | 11 ++ .../tutorial004_an_py310.py | 15 ++ .../tutorial004_py310.py | 13 ++ .../tutorial005_an_py310.py | 16 ++ .../tutorial005_py310.py | 15 ++ ...001_an_py39.py => tutorial006_an_py310.py} | 10 +- ...torial001_py39.py => tutorial006_py310.py} | 10 +- .../pydantic_v1_in_v2/tutorial001_an_py39.py | 9 - .../pydantic_v1_in_v2/tutorial002_an_py39.py | 18 -- .../pydantic_v1_in_v2/tutorial003_an_py39.py | 25 --- .../pydantic_v1_in_v2/tutorial004_an_py39.py | 19 -- docs_src/python_types/tutorial001_py310.py | 6 + docs_src/python_types/tutorial002_py310.py | 6 + docs_src/python_types/tutorial003_py310.py | 3 + docs_src/python_types/tutorial004_py310.py | 3 + docs_src/python_types/tutorial005_py310.py | 2 + docs_src/python_types/tutorial006_py310.py | 3 + docs_src/python_types/tutorial007_py310.py | 2 + docs_src/python_types/tutorial008_py310.py | 4 + docs_src/python_types/tutorial010_py310.py | 7 + docs_src/python_types/tutorial011_py39.py | 23 --- docs_src/python_types/tutorial012_py39.py | 8 - docs_src/python_types/tutorial013_py310.py | 5 + .../query_param_models/tutorial001_an_py39.py | 18 -- .../query_param_models/tutorial001_py39.py | 18 -- .../query_param_models/tutorial002_an_py39.py | 20 -- .../query_param_models/tutorial002_py39.py | 20 -- docs_src/query_params/tutorial001_py310.py | 10 + docs_src/query_params/tutorial002_py39.py | 12 -- docs_src/query_params/tutorial003_py39.py | 17 -- docs_src/query_params/tutorial004_py39.py | 19 -- docs_src/query_params/tutorial005_py310.py | 9 + docs_src/query_params/tutorial006_py39.py | 13 -- .../tutorial001_py39.py | 13 -- .../tutorial002_an_py39.py | 13 -- .../tutorial003_an_py39.py | 15 -- .../tutorial003_py39.py | 15 -- .../tutorial004_an_py39.py | 17 -- .../tutorial004_py39.py | 17 -- .../tutorial004_regex_an_py310.py | 17 -- ...ial002_py39.py => tutorial005_an_py310.py} | 4 +- ...torial009_py39.py => tutorial005_py310.py} | 4 +- ...al006c_py39.py => tutorial006_an_py310.py} | 4 +- ...al006c_an_py39.py => tutorial006_py310.py} | 4 +- .../tutorial007_an_py39.py | 15 -- .../tutorial007_py39.py | 15 -- .../tutorial008_an_py39.py | 22 --- .../tutorial008_py39.py | 20 -- .../tutorial009_an_py39.py | 13 -- .../tutorial010_an_py39.py | 26 --- .../tutorial010_py39.py | 24 --- ...011_an_py39.py => tutorial012_an_py310.py} | 4 +- .../tutorial012_py310.py | 9 + ...ial011_py39.py => tutorial013_an_py310.py} | 4 +- .../tutorial013_py310.py | 9 + .../tutorial014_an_py39.py | 15 -- .../tutorial014_py39.py | 15 -- .../tutorial015_an_py39.py | 30 --- .../request_files/tutorial001_02_an_py39.py | 21 -- docs_src/request_files/tutorial001_02_py39.py | 21 -- .../request_files/tutorial001_03_an_py310.py | 17 ++ .../request_files/tutorial001_03_py310.py | 15 ++ .../request_files/tutorial001_an_py310.py | 15 ++ docs_src/request_files/tutorial001_py310.py | 13 ++ .../request_files/tutorial002_an_py310.py | 33 ++++ docs_src/request_files/tutorial002_py310.py | 31 +++ .../request_files/tutorial003_an_py310.py | 39 ++++ docs_src/request_files/tutorial003_py310.py | 35 ++++ .../tutorial001_an_py310.py | 16 ++ .../request_form_models/tutorial001_py310.py | 14 ++ .../tutorial002_an_py310.py | 17 ++ .../request_form_models/tutorial002_py310.py | 15 ++ .../request_forms/tutorial001_an_py310.py | 10 + docs_src/request_forms/tutorial001_py310.py | 8 + .../tutorial001_an_py310.py | 18 ++ .../tutorial001_py310.py | 14 ++ .../tutorial001_py310.py | 13 ++ .../response_cookies/tutorial001_py310.py | 12 ++ .../response_cookies/tutorial002_py310.py | 9 + .../response_directly/tutorial001_py39.py | 22 --- .../response_directly/tutorial002_py310.py | 18 ++ .../response_headers/tutorial001_py310.py | 11 ++ .../response_headers/tutorial002_py310.py | 9 + .../response_model/tutorial001_01_py39.py | 27 --- docs_src/response_model/tutorial001_py39.py | 27 --- docs_src/response_model/tutorial002_py39.py | 19 -- .../response_model/tutorial003_01_py39.py | 21 -- .../response_model/tutorial003_02_py310.py | 11 ++ .../response_model/tutorial003_03_py310.py | 9 + .../response_model/tutorial003_04_py39.py | 13 -- .../response_model/tutorial003_05_py39.py | 13 -- docs_src/response_model/tutorial003_py39.py | 24 --- docs_src/response_model/tutorial004_py39.py | 26 --- docs_src/response_model/tutorial005_py39.py | 39 ---- docs_src/response_model/tutorial006_py39.py | 39 ---- .../response_status_code/tutorial001_py310.py | 8 + .../response_status_code/tutorial002_py310.py | 8 + .../tutorial001_pv1_py310.py | 29 --- .../tutorial001_pv1_py39.py | 31 --- .../schema_extra_example/tutorial001_py39.py | 32 ---- .../schema_extra_example/tutorial002_py39.py | 19 -- .../tutorial003_an_py39.py | 34 ---- .../schema_extra_example/tutorial003_py39.py | 31 --- .../tutorial004_an_py39.py | 43 ----- .../schema_extra_example/tutorial004_py39.py | 40 ---- .../tutorial005_an_py39.py | 54 ------ .../schema_extra_example/tutorial005_py39.py | 51 ----- docs_src/security/tutorial001_an_py310.py | 13 ++ docs_src/security/tutorial001_py310.py | 11 ++ docs_src/security/tutorial002_an_py39.py | 32 ---- docs_src/security/tutorial002_py39.py | 32 ---- docs_src/security/tutorial003_an_py39.py | 94 --------- docs_src/security/tutorial003_py39.py | 90 --------- docs_src/security/tutorial004_an_py39.py | 147 -------------- docs_src/security/tutorial004_py39.py | 141 -------------- docs_src/security/tutorial005_an_py39.py | 179 ------------------ docs_src/security/tutorial005_py39.py | 177 ----------------- docs_src/security/tutorial006_an_py310.py | 13 ++ docs_src/security/tutorial006_py310.py | 11 ++ docs_src/security/tutorial007_an_py310.py | 36 ++++ docs_src/security/tutorial007_py310.py | 33 ++++ .../tutorial001_py39.py | 28 --- .../tutorial002_py39.py | 28 --- docs_src/settings/app01_py310/__init__.py | 0 .../config_pv1.py => app01_py310/config.py} | 6 +- docs_src/settings/app01_py310/main.py | 14 ++ docs_src/settings/app02_an_py310/__init__.py | 0 .../config.py} | 5 +- docs_src/settings/app02_an_py310/main.py | 22 +++ docs_src/settings/app02_an_py310/test_main.py | 23 +++ docs_src/settings/app02_py310/__init__.py | 0 docs_src/settings/app02_py310/config.py | 7 + docs_src/settings/app02_py310/main.py | 21 ++ docs_src/settings/app02_py310/test_main.py | 23 +++ docs_src/settings/app03_an_py310/__init__.py | 0 docs_src/settings/app03_an_py310/config.py | 9 + docs_src/settings/app03_an_py310/main.py | 22 +++ docs_src/settings/app03_py310/__init__.py | 0 docs_src/settings/app03_py310/config.py | 9 + docs_src/settings/app03_py310/main.py | 21 ++ ...al001_pv1_py39.py => tutorial001_py310.py} | 2 +- docs_src/sql_databases/tutorial001_an_py39.py | 73 ------- docs_src/sql_databases/tutorial001_py39.py | 71 ------- docs_src/sql_databases/tutorial002_an_py39.py | 103 ---------- docs_src/sql_databases/tutorial002_py39.py | 104 ---------- docs_src/static_files/tutorial001_py310.py | 6 + .../sub_applications/tutorial001_py310.py | 19 ++ docs_src/templates/tutorial001_py310.py | 18 ++ .../tutorial001_py310.py | 9 + docs_src/websockets/tutorial001_py310.py | 51 +++++ docs_src/websockets/tutorial002_an_py39.py | 92 --------- docs_src/websockets/tutorial002_py39.py | 91 --------- docs_src/websockets/tutorial003_py310.py | 81 ++++++++ docs_src/wsgi/tutorial001_py310.py | 23 +++ pyproject.toml | 40 ++-- 420 files changed, 3347 insertions(+), 5282 deletions(-) create mode 100644 docs_src/additional_responses/tutorial001_py310.py delete mode 100644 docs_src/additional_responses/tutorial002_py39.py create mode 100644 docs_src/additional_responses/tutorial003_py310.py delete mode 100644 docs_src/additional_responses/tutorial004_py39.py delete mode 100644 docs_src/additional_status_codes/tutorial001_an_py39.py delete mode 100644 docs_src/additional_status_codes/tutorial001_py39.py create mode 100644 docs_src/advanced_middleware/tutorial001_py310.py create mode 100644 docs_src/advanced_middleware/tutorial002_py310.py create mode 100644 docs_src/advanced_middleware/tutorial003_py310.py create mode 100644 docs_src/app_testing/app_a_py310/__init__.py create mode 100644 docs_src/app_testing/app_a_py310/main.py create mode 100644 docs_src/app_testing/app_a_py310/test_main.py delete mode 100644 docs_src/app_testing/app_b_an_py39/main.py delete mode 100644 docs_src/app_testing/app_b_an_py39/test_main.py delete mode 100644 docs_src/app_testing/app_b_py39/main.py delete mode 100644 docs_src/app_testing/app_b_py39/test_main.py create mode 100644 docs_src/app_testing/tutorial001_py310.py create mode 100644 docs_src/app_testing/tutorial002_py310.py create mode 100644 docs_src/app_testing/tutorial003_py310.py create mode 100644 docs_src/app_testing/tutorial004_py310.py create mode 100644 docs_src/async_tests/app_a_py310/__init__.py create mode 100644 docs_src/async_tests/app_a_py310/main.py create mode 100644 docs_src/async_tests/app_a_py310/test_main.py create mode 100644 docs_src/authentication_error_status_code/tutorial001_an_py310.py create mode 100644 docs_src/background_tasks/tutorial001_py310.py delete mode 100644 docs_src/background_tasks/tutorial002_an_py39.py delete mode 100644 docs_src/background_tasks/tutorial002_py39.py create mode 100644 docs_src/behind_a_proxy/tutorial001_01_py310.py create mode 100644 docs_src/behind_a_proxy/tutorial001_py310.py create mode 100644 docs_src/behind_a_proxy/tutorial002_py310.py create mode 100644 docs_src/behind_a_proxy/tutorial003_py310.py create mode 100644 docs_src/behind_a_proxy/tutorial004_py310.py create mode 100644 docs_src/bigger_applications/app_an_py310/__init__.py create mode 100644 docs_src/bigger_applications/app_an_py310/dependencies.py create mode 100644 docs_src/bigger_applications/app_an_py310/internal/__init__.py rename docs_src/bigger_applications/{app_py39 => app_an_py310}/internal/admin.py (100%) create mode 100644 docs_src/bigger_applications/app_an_py310/main.py create mode 100644 docs_src/bigger_applications/app_an_py310/routers/__init__.py rename docs_src/bigger_applications/{app_py39 => app_an_py310}/routers/items.py (100%) rename docs_src/bigger_applications/{app_py39 => app_an_py310}/routers/users.py (100%) create mode 100644 docs_src/bigger_applications/app_py310/__init__.py create mode 100644 docs_src/bigger_applications/app_py310/dependencies.py create mode 100644 docs_src/bigger_applications/app_py310/internal/__init__.py create mode 100644 docs_src/bigger_applications/app_py310/main.py create mode 100644 docs_src/bigger_applications/app_py310/routers/__init__.py delete mode 100644 docs_src/body/tutorial001_py39.py delete mode 100644 docs_src/body/tutorial002_py39.py delete mode 100644 docs_src/body/tutorial003_py39.py delete mode 100644 docs_src/body/tutorial004_py39.py delete mode 100644 docs_src/body_fields/tutorial001_an_py39.py delete mode 100644 docs_src/body_fields/tutorial001_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial001_an_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial001_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial002_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial003_an_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial003_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial004_an_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial004_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial005_an_py39.py delete mode 100644 docs_src/body_multiple_params/tutorial005_py39.py delete mode 100644 docs_src/body_nested_models/tutorial001_py39.py delete mode 100644 docs_src/body_nested_models/tutorial002_py39.py delete mode 100644 docs_src/body_nested_models/tutorial003_py39.py delete mode 100644 docs_src/body_nested_models/tutorial004_py39.py delete mode 100644 docs_src/body_nested_models/tutorial005_py39.py delete mode 100644 docs_src/body_nested_models/tutorial006_py39.py delete mode 100644 docs_src/body_nested_models/tutorial007_py39.py create mode 100644 docs_src/body_nested_models/tutorial008_py310.py create mode 100644 docs_src/body_nested_models/tutorial009_py310.py delete mode 100644 docs_src/body_updates/tutorial001_py39.py delete mode 100644 docs_src/body_updates/tutorial002_py39.py create mode 100644 docs_src/conditional_openapi/tutorial001_py310.py create mode 100644 docs_src/configure_swagger_ui/tutorial001_py310.py create mode 100644 docs_src/configure_swagger_ui/tutorial002_py310.py create mode 100644 docs_src/configure_swagger_ui/tutorial003_py310.py delete mode 100644 docs_src/cookie_param_models/tutorial001_an_py39.py delete mode 100644 docs_src/cookie_param_models/tutorial001_py39.py delete mode 100644 docs_src/cookie_param_models/tutorial002_an_py39.py delete mode 100644 docs_src/cookie_param_models/tutorial002_py39.py delete mode 100644 docs_src/cookie_params/tutorial001_an_py39.py delete mode 100644 docs_src/cookie_params/tutorial001_py39.py create mode 100644 docs_src/cors/tutorial001_py310.py create mode 100644 docs_src/custom_docs_ui/tutorial001_py310.py create mode 100644 docs_src/custom_docs_ui/tutorial002_py310.py delete mode 100644 docs_src/custom_request_and_route/tutorial001_an_py39.py delete mode 100644 docs_src/custom_request_and_route/tutorial001_py39.py delete mode 100644 docs_src/custom_request_and_route/tutorial002_an_py39.py delete mode 100644 docs_src/custom_request_and_route/tutorial002_py39.py delete mode 100644 docs_src/custom_request_and_route/tutorial003_py39.py create mode 100644 docs_src/custom_response/tutorial001_py310.py create mode 100644 docs_src/custom_response/tutorial001b_py310.py create mode 100644 docs_src/custom_response/tutorial002_py310.py create mode 100644 docs_src/custom_response/tutorial003_py310.py create mode 100644 docs_src/custom_response/tutorial004_py310.py create mode 100644 docs_src/custom_response/tutorial005_py310.py create mode 100644 docs_src/custom_response/tutorial006_py310.py create mode 100644 docs_src/custom_response/tutorial006b_py310.py create mode 100644 docs_src/custom_response/tutorial006c_py310.py create mode 100644 docs_src/custom_response/tutorial007_py310.py create mode 100644 docs_src/custom_response/tutorial008_py310.py create mode 100644 docs_src/custom_response/tutorial009_py310.py create mode 100644 docs_src/custom_response/tutorial009b_py310.py create mode 100644 docs_src/custom_response/tutorial009c_py310.py create mode 100644 docs_src/custom_response/tutorial010_py310.py delete mode 100644 docs_src/dataclasses_/tutorial001_py39.py delete mode 100644 docs_src/dataclasses_/tutorial002_py39.py delete mode 100644 docs_src/dataclasses_/tutorial003_py39.py create mode 100644 docs_src/debugging/tutorial001_py310.py delete mode 100644 docs_src/dependencies/tutorial001_02_an_py39.py delete mode 100644 docs_src/dependencies/tutorial001_an_py39.py delete mode 100644 docs_src/dependencies/tutorial001_py39.py delete mode 100644 docs_src/dependencies/tutorial002_an_py39.py delete mode 100644 docs_src/dependencies/tutorial002_py39.py delete mode 100644 docs_src/dependencies/tutorial003_an_py39.py delete mode 100644 docs_src/dependencies/tutorial003_py39.py delete mode 100644 docs_src/dependencies/tutorial004_an_py39.py delete mode 100644 docs_src/dependencies/tutorial004_py39.py delete mode 100644 docs_src/dependencies/tutorial005_an_py39.py delete mode 100644 docs_src/dependencies/tutorial005_py39.py create mode 100644 docs_src/dependencies/tutorial006_an_py310.py create mode 100644 docs_src/dependencies/tutorial006_py310.py create mode 100644 docs_src/dependencies/tutorial007_py310.py create mode 100644 docs_src/dependencies/tutorial008_an_py310.py create mode 100644 docs_src/dependencies/tutorial008_py310.py create mode 100644 docs_src/dependencies/tutorial008b_an_py310.py create mode 100644 docs_src/dependencies/tutorial008b_py310.py create mode 100644 docs_src/dependencies/tutorial008c_an_py310.py create mode 100644 docs_src/dependencies/tutorial008c_py310.py create mode 100644 docs_src/dependencies/tutorial008d_an_py310.py create mode 100644 docs_src/dependencies/tutorial008d_py310.py create mode 100644 docs_src/dependencies/tutorial008e_an_py310.py create mode 100644 docs_src/dependencies/tutorial008e_py310.py create mode 100644 docs_src/dependencies/tutorial010_py310.py create mode 100644 docs_src/dependencies/tutorial011_an_py310.py create mode 100644 docs_src/dependencies/tutorial011_py310.py create mode 100644 docs_src/dependencies/tutorial012_an_py310.py create mode 100644 docs_src/dependencies/tutorial012_py310.py delete mode 100644 docs_src/dependency_testing/tutorial001_an_py39.py delete mode 100644 docs_src/dependency_testing/tutorial001_py39.py delete mode 100644 docs_src/encoder/tutorial001_py39.py create mode 100644 docs_src/events/tutorial001_py310.py create mode 100644 docs_src/events/tutorial002_py310.py create mode 100644 docs_src/events/tutorial003_py310.py create mode 100644 docs_src/extending_openapi/tutorial001_py310.py delete mode 100644 docs_src/extra_data_types/tutorial001_an_py39.py delete mode 100644 docs_src/extra_data_types/tutorial001_py39.py delete mode 100644 docs_src/extra_models/tutorial001_py39.py delete mode 100644 docs_src/extra_models/tutorial002_py39.py delete mode 100644 docs_src/extra_models/tutorial003_py39.py create mode 100644 docs_src/extra_models/tutorial004_py310.py create mode 100644 docs_src/extra_models/tutorial005_py310.py create mode 100644 docs_src/first_steps/tutorial001_py310.py create mode 100644 docs_src/first_steps/tutorial003_py310.py create mode 100644 docs_src/generate_clients/tutorial001_py310.py create mode 100644 docs_src/generate_clients/tutorial002_py310.py create mode 100644 docs_src/generate_clients/tutorial003_py310.py create mode 100644 docs_src/generate_clients/tutorial004_py310.py create mode 100644 docs_src/graphql_/tutorial001_py310.py create mode 100644 docs_src/handling_errors/tutorial001_py310.py create mode 100644 docs_src/handling_errors/tutorial002_py310.py create mode 100644 docs_src/handling_errors/tutorial003_py310.py create mode 100644 docs_src/handling_errors/tutorial004_py310.py create mode 100644 docs_src/handling_errors/tutorial005_py310.py create mode 100644 docs_src/handling_errors/tutorial006_py310.py delete mode 100644 docs_src/header_param_models/tutorial001_an_py39.py delete mode 100644 docs_src/header_param_models/tutorial001_py39.py delete mode 100644 docs_src/header_param_models/tutorial002_an_py39.py delete mode 100644 docs_src/header_param_models/tutorial002_py39.py delete mode 100644 docs_src/header_param_models/tutorial003_an_py39.py delete mode 100644 docs_src/header_param_models/tutorial003_py39.py delete mode 100644 docs_src/header_params/tutorial001_an_py39.py delete mode 100644 docs_src/header_params/tutorial001_py39.py delete mode 100644 docs_src/header_params/tutorial002_an_py39.py delete mode 100644 docs_src/header_params/tutorial002_py39.py delete mode 100644 docs_src/header_params/tutorial003_an_py39.py delete mode 100644 docs_src/header_params/tutorial003_py39.py create mode 100644 docs_src/metadata/tutorial001_1_py310.py create mode 100644 docs_src/metadata/tutorial001_py310.py create mode 100644 docs_src/metadata/tutorial002_py310.py create mode 100644 docs_src/metadata/tutorial003_py310.py create mode 100644 docs_src/metadata/tutorial004_py310.py create mode 100644 docs_src/middleware/tutorial001_py310.py delete mode 100644 docs_src/openapi_callbacks/tutorial001_py39.py create mode 100644 docs_src/openapi_webhooks/tutorial001_py310.py create mode 100644 docs_src/path_operation_advanced_configuration/tutorial001_py310.py create mode 100644 docs_src/path_operation_advanced_configuration/tutorial002_py310.py create mode 100644 docs_src/path_operation_advanced_configuration/tutorial003_py310.py delete mode 100644 docs_src/path_operation_advanced_configuration/tutorial004_py39.py create mode 100644 docs_src/path_operation_advanced_configuration/tutorial005_py310.py create mode 100644 docs_src/path_operation_advanced_configuration/tutorial006_py310.py rename docs_src/path_operation_advanced_configuration/{tutorial007_pv1_py39.py => tutorial007_py310.py} (68%) delete mode 100644 docs_src/path_operation_configuration/tutorial001_py39.py delete mode 100644 docs_src/path_operation_configuration/tutorial002_py39.py create mode 100644 docs_src/path_operation_configuration/tutorial002b_py310.py delete mode 100644 docs_src/path_operation_configuration/tutorial003_py39.py delete mode 100644 docs_src/path_operation_configuration/tutorial004_py39.py delete mode 100644 docs_src/path_operation_configuration/tutorial005_py39.py create mode 100644 docs_src/path_operation_configuration/tutorial006_py310.py create mode 100644 docs_src/path_params/tutorial001_py310.py create mode 100644 docs_src/path_params/tutorial002_py310.py create mode 100644 docs_src/path_params/tutorial003_py310.py create mode 100644 docs_src/path_params/tutorial003b_py310.py create mode 100644 docs_src/path_params/tutorial004_py310.py create mode 100644 docs_src/path_params/tutorial005_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial002_an_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial002_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial003_an_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial003_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial004_an_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial004_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial005_an_py310.py create mode 100644 docs_src/path_params_numeric_validations/tutorial005_py310.py rename docs_src/path_params_numeric_validations/{tutorial001_an_py39.py => tutorial006_an_py310.py} (61%) rename docs_src/path_params_numeric_validations/{tutorial001_py39.py => tutorial006_py310.py} (53%) delete mode 100644 docs_src/pydantic_v1_in_v2/tutorial001_an_py39.py delete mode 100644 docs_src/pydantic_v1_in_v2/tutorial002_an_py39.py delete mode 100644 docs_src/pydantic_v1_in_v2/tutorial003_an_py39.py delete mode 100644 docs_src/pydantic_v1_in_v2/tutorial004_an_py39.py create mode 100644 docs_src/python_types/tutorial001_py310.py create mode 100644 docs_src/python_types/tutorial002_py310.py create mode 100644 docs_src/python_types/tutorial003_py310.py create mode 100644 docs_src/python_types/tutorial004_py310.py create mode 100644 docs_src/python_types/tutorial005_py310.py create mode 100644 docs_src/python_types/tutorial006_py310.py create mode 100644 docs_src/python_types/tutorial007_py310.py create mode 100644 docs_src/python_types/tutorial008_py310.py create mode 100644 docs_src/python_types/tutorial010_py310.py delete mode 100644 docs_src/python_types/tutorial011_py39.py delete mode 100644 docs_src/python_types/tutorial012_py39.py create mode 100644 docs_src/python_types/tutorial013_py310.py delete mode 100644 docs_src/query_param_models/tutorial001_an_py39.py delete mode 100644 docs_src/query_param_models/tutorial001_py39.py delete mode 100644 docs_src/query_param_models/tutorial002_an_py39.py delete mode 100644 docs_src/query_param_models/tutorial002_py39.py create mode 100644 docs_src/query_params/tutorial001_py310.py delete mode 100644 docs_src/query_params/tutorial002_py39.py delete mode 100644 docs_src/query_params/tutorial003_py39.py delete mode 100644 docs_src/query_params/tutorial004_py39.py create mode 100644 docs_src/query_params/tutorial005_py310.py delete mode 100644 docs_src/query_params/tutorial006_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial001_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial002_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial003_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial003_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial004_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial004_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial004_regex_an_py310.py rename docs_src/query_params_str_validations/{tutorial002_py39.py => tutorial005_an_py310.py} (65%) rename docs_src/query_params_str_validations/{tutorial009_py39.py => tutorial005_py310.py} (64%) rename docs_src/query_params_str_validations/{tutorial006c_py39.py => tutorial006_an_py310.py} (69%) rename docs_src/query_params_str_validations/{tutorial006c_an_py39.py => tutorial006_py310.py} (64%) delete mode 100644 docs_src/query_params_str_validations/tutorial007_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial007_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial008_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial008_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial009_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial010_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial010_py39.py rename docs_src/query_params_str_validations/{tutorial011_an_py39.py => tutorial012_an_py310.py} (52%) create mode 100644 docs_src/query_params_str_validations/tutorial012_py310.py rename docs_src/query_params_str_validations/{tutorial011_py39.py => tutorial013_an_py310.py} (56%) create mode 100644 docs_src/query_params_str_validations/tutorial013_py310.py delete mode 100644 docs_src/query_params_str_validations/tutorial014_an_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial014_py39.py delete mode 100644 docs_src/query_params_str_validations/tutorial015_an_py39.py delete mode 100644 docs_src/request_files/tutorial001_02_an_py39.py delete mode 100644 docs_src/request_files/tutorial001_02_py39.py create mode 100644 docs_src/request_files/tutorial001_03_an_py310.py create mode 100644 docs_src/request_files/tutorial001_03_py310.py create mode 100644 docs_src/request_files/tutorial001_an_py310.py create mode 100644 docs_src/request_files/tutorial001_py310.py create mode 100644 docs_src/request_files/tutorial002_an_py310.py create mode 100644 docs_src/request_files/tutorial002_py310.py create mode 100644 docs_src/request_files/tutorial003_an_py310.py create mode 100644 docs_src/request_files/tutorial003_py310.py create mode 100644 docs_src/request_form_models/tutorial001_an_py310.py create mode 100644 docs_src/request_form_models/tutorial001_py310.py create mode 100644 docs_src/request_form_models/tutorial002_an_py310.py create mode 100644 docs_src/request_form_models/tutorial002_py310.py create mode 100644 docs_src/request_forms/tutorial001_an_py310.py create mode 100644 docs_src/request_forms/tutorial001_py310.py create mode 100644 docs_src/request_forms_and_files/tutorial001_an_py310.py create mode 100644 docs_src/request_forms_and_files/tutorial001_py310.py create mode 100644 docs_src/response_change_status_code/tutorial001_py310.py create mode 100644 docs_src/response_cookies/tutorial001_py310.py create mode 100644 docs_src/response_cookies/tutorial002_py310.py delete mode 100644 docs_src/response_directly/tutorial001_py39.py create mode 100644 docs_src/response_directly/tutorial002_py310.py create mode 100644 docs_src/response_headers/tutorial001_py310.py create mode 100644 docs_src/response_headers/tutorial002_py310.py delete mode 100644 docs_src/response_model/tutorial001_01_py39.py delete mode 100644 docs_src/response_model/tutorial001_py39.py delete mode 100644 docs_src/response_model/tutorial002_py39.py delete mode 100644 docs_src/response_model/tutorial003_01_py39.py create mode 100644 docs_src/response_model/tutorial003_02_py310.py create mode 100644 docs_src/response_model/tutorial003_03_py310.py delete mode 100644 docs_src/response_model/tutorial003_04_py39.py delete mode 100644 docs_src/response_model/tutorial003_05_py39.py delete mode 100644 docs_src/response_model/tutorial003_py39.py delete mode 100644 docs_src/response_model/tutorial004_py39.py delete mode 100644 docs_src/response_model/tutorial005_py39.py delete mode 100644 docs_src/response_model/tutorial006_py39.py create mode 100644 docs_src/response_status_code/tutorial001_py310.py create mode 100644 docs_src/response_status_code/tutorial002_py310.py delete mode 100644 docs_src/schema_extra_example/tutorial001_pv1_py310.py delete mode 100644 docs_src/schema_extra_example/tutorial001_pv1_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial001_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial002_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial003_an_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial003_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial004_an_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial004_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial005_an_py39.py delete mode 100644 docs_src/schema_extra_example/tutorial005_py39.py create mode 100644 docs_src/security/tutorial001_an_py310.py create mode 100644 docs_src/security/tutorial001_py310.py delete mode 100644 docs_src/security/tutorial002_an_py39.py delete mode 100644 docs_src/security/tutorial002_py39.py delete mode 100644 docs_src/security/tutorial003_an_py39.py delete mode 100644 docs_src/security/tutorial003_py39.py delete mode 100644 docs_src/security/tutorial004_an_py39.py delete mode 100644 docs_src/security/tutorial004_py39.py delete mode 100644 docs_src/security/tutorial005_an_py39.py delete mode 100644 docs_src/security/tutorial005_py39.py create mode 100644 docs_src/security/tutorial006_an_py310.py create mode 100644 docs_src/security/tutorial006_py310.py create mode 100644 docs_src/security/tutorial007_an_py310.py create mode 100644 docs_src/security/tutorial007_py310.py delete mode 100644 docs_src/separate_openapi_schemas/tutorial001_py39.py delete mode 100644 docs_src/separate_openapi_schemas/tutorial002_py39.py create mode 100644 docs_src/settings/app01_py310/__init__.py rename docs_src/settings/{app03_an_py39/config_pv1.py => app01_py310/config.py} (59%) create mode 100644 docs_src/settings/app01_py310/main.py create mode 100644 docs_src/settings/app02_an_py310/__init__.py rename docs_src/settings/{app03_py39/config_pv1.py => app02_an_py310/config.py} (58%) create mode 100644 docs_src/settings/app02_an_py310/main.py create mode 100644 docs_src/settings/app02_an_py310/test_main.py create mode 100644 docs_src/settings/app02_py310/__init__.py create mode 100644 docs_src/settings/app02_py310/config.py create mode 100644 docs_src/settings/app02_py310/main.py create mode 100644 docs_src/settings/app02_py310/test_main.py create mode 100644 docs_src/settings/app03_an_py310/__init__.py create mode 100644 docs_src/settings/app03_an_py310/config.py create mode 100644 docs_src/settings/app03_an_py310/main.py create mode 100644 docs_src/settings/app03_py310/__init__.py create mode 100644 docs_src/settings/app03_py310/config.py create mode 100644 docs_src/settings/app03_py310/main.py rename docs_src/settings/{tutorial001_pv1_py39.py => tutorial001_py310.py} (89%) delete mode 100644 docs_src/sql_databases/tutorial001_an_py39.py delete mode 100644 docs_src/sql_databases/tutorial001_py39.py delete mode 100644 docs_src/sql_databases/tutorial002_an_py39.py delete mode 100644 docs_src/sql_databases/tutorial002_py39.py create mode 100644 docs_src/static_files/tutorial001_py310.py create mode 100644 docs_src/sub_applications/tutorial001_py310.py create mode 100644 docs_src/templates/tutorial001_py310.py create mode 100644 docs_src/using_request_directly/tutorial001_py310.py create mode 100644 docs_src/websockets/tutorial001_py310.py delete mode 100644 docs_src/websockets/tutorial002_an_py39.py delete mode 100644 docs_src/websockets/tutorial002_py39.py create mode 100644 docs_src/websockets/tutorial003_py310.py create mode 100644 docs_src/wsgi/tutorial001_py310.py diff --git a/docs/en/docs/advanced/additional-responses.md b/docs/en/docs/advanced/additional-responses.md index bb70753ed..6306bd1f9 100644 --- a/docs/en/docs/advanced/additional-responses.md +++ b/docs/en/docs/advanced/additional-responses.md @@ -26,7 +26,7 @@ Each of those response `dict`s can have a key `model`, containing a Pydantic mod For example, to declare another response with a status code `404` and a Pydantic model `Message`, you can write: -{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *} +{* ../../docs_src/additional_responses/tutorial001_py310.py hl[18,22] *} /// note @@ -203,7 +203,7 @@ For example, you can declare a response with a status code `404` that uses a Pyd And a response with a status code `200` that uses your `response_model`, but includes a custom `example`: -{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *} +{* ../../docs_src/additional_responses/tutorial003_py310.py hl[20:31] *} It will all be combined and included in your OpenAPI, and shown in the API docs: diff --git a/docs/en/docs/advanced/advanced-dependencies.md b/docs/en/docs/advanced/advanced-dependencies.md index 0d03507b7..3a23a6d1a 100644 --- a/docs/en/docs/advanced/advanced-dependencies.md +++ b/docs/en/docs/advanced/advanced-dependencies.md @@ -18,7 +18,7 @@ Not the class itself (which is already a callable), but an instance of that clas To do that, we declare a method `__call__`: -{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[12] *} +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[12] *} In this case, this `__call__` is what **FastAPI** will use to check for additional parameters and sub-dependencies, and this is what will be called to pass a value to the parameter in your *path operation function* later. @@ -26,7 +26,7 @@ In this case, this `__call__` is what **FastAPI** will use to check for addition And now, we can use `__init__` to declare the parameters of the instance that we can use to "parameterize" the dependency: -{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[9] *} +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[9] *} In this case, **FastAPI** won't ever touch or care about `__init__`, we will use it directly in our code. @@ -34,7 +34,7 @@ In this case, **FastAPI** won't ever touch or care about `__init__`, we will use We could create an instance of this class with: -{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[18] *} +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[18] *} And that way we are able to "parameterize" our dependency, that now has `"bar"` inside of it, as the attribute `checker.fixed_content`. @@ -50,7 +50,7 @@ checker(q="somequery") ...and pass whatever that returns as the value of the dependency in our *path operation function* as the parameter `fixed_content_included`: -{* ../../docs_src/dependencies/tutorial011_an_py39.py hl[22] *} +{* ../../docs_src/dependencies/tutorial011_an_py310.py hl[22] *} /// tip diff --git a/docs/en/docs/advanced/async-tests.md b/docs/en/docs/advanced/async-tests.md index 65ddc60b2..cefb1d184 100644 --- a/docs/en/docs/advanced/async-tests.md +++ b/docs/en/docs/advanced/async-tests.md @@ -32,11 +32,11 @@ For a simple example, let's consider a file structure similar to the one describ The file `main.py` would have: -{* ../../docs_src/async_tests/app_a_py39/main.py *} +{* ../../docs_src/async_tests/app_a_py310/main.py *} The file `test_main.py` would have the tests for `main.py`, it could look like this now: -{* ../../docs_src/async_tests/app_a_py39/test_main.py *} +{* ../../docs_src/async_tests/app_a_py310/test_main.py *} ## Run it { #run-it } @@ -56,7 +56,7 @@ $ pytest The marker `@pytest.mark.anyio` tells pytest that this test function should be called asynchronously: -{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *} +{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[7] *} /// tip @@ -66,7 +66,7 @@ Note that the test function is now `async def` instead of just `def` as before w Then we can create an `AsyncClient` with the app, and send async requests to it, using `await`. -{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *} +{* ../../docs_src/async_tests/app_a_py310/test_main.py hl[9:12] *} This is the equivalent to: diff --git a/docs/en/docs/advanced/behind-a-proxy.md b/docs/en/docs/advanced/behind-a-proxy.md index 4fef02bd1..770e9cd3c 100644 --- a/docs/en/docs/advanced/behind-a-proxy.md +++ b/docs/en/docs/advanced/behind-a-proxy.md @@ -44,7 +44,7 @@ $ fastapi run --forwarded-allow-ips="*" For example, let's say you define a *path operation* `/items/`: -{* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *} +{* ../../docs_src/behind_a_proxy/tutorial001_01_py310.py hl[6] *} If the client tries to go to `/items`, by default, it would be redirected to `/items/`. @@ -115,7 +115,7 @@ In this case, the original path `/app` would actually be served at `/api/v1/app` Even though all your code is written assuming there's just `/app`. -{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *} +{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[6] *} And the proxy would be **"stripping"** the **path prefix** on the fly before transmitting the request to the app server (probably Uvicorn via FastAPI CLI), keeping your application convinced that it is being served at `/app`, so that you don't have to update all your code to include the prefix `/api/v1`. @@ -193,7 +193,7 @@ You can get the current `root_path` used by your application for each request, i Here we are including it in the message just for demonstration purposes. -{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *} +{* ../../docs_src/behind_a_proxy/tutorial001_py310.py hl[8] *} Then, if you start Uvicorn with: @@ -220,7 +220,7 @@ The response would be something like: Alternatively, if you don't have a way to provide a command line option like `--root-path` or equivalent, you can set the `root_path` parameter when creating your FastAPI app: -{* ../../docs_src/behind_a_proxy/tutorial002_py39.py hl[3] *} +{* ../../docs_src/behind_a_proxy/tutorial002_py310.py hl[3] *} Passing the `root_path` to `FastAPI` would be the equivalent of passing the `--root-path` command line option to Uvicorn or Hypercorn. @@ -400,7 +400,7 @@ If you pass a custom list of `servers` and there's a `root_path` (because your A For example: -{* ../../docs_src/behind_a_proxy/tutorial003_py39.py hl[4:7] *} +{* ../../docs_src/behind_a_proxy/tutorial003_py310.py hl[4:7] *} Will generate an OpenAPI schema like: @@ -455,7 +455,7 @@ If you don't specify the `servers` parameter and `root_path` is equal to `/`, th If you don't want **FastAPI** to include an automatic server using the `root_path`, you can use the parameter `root_path_in_servers=False`: -{* ../../docs_src/behind_a_proxy/tutorial004_py39.py hl[9] *} +{* ../../docs_src/behind_a_proxy/tutorial004_py310.py hl[9] *} and then it won't include it in the OpenAPI schema. diff --git a/docs/en/docs/advanced/custom-response.md b/docs/en/docs/advanced/custom-response.md index e53409c39..8b4b3da33 100644 --- a/docs/en/docs/advanced/custom-response.md +++ b/docs/en/docs/advanced/custom-response.md @@ -30,7 +30,7 @@ This is because by default, FastAPI will inspect every item inside and make sure But if you are certain that the content that you are returning is **serializable with JSON**, you can pass it directly to the response class and avoid the extra overhead that FastAPI would have by passing your return content through the `jsonable_encoder` before passing it to the response class. -{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial001b_py310.py hl[2,7] *} /// info @@ -55,7 +55,7 @@ To return a response with HTML directly from **FastAPI**, use `HTMLResponse`. * Import `HTMLResponse`. * Pass `HTMLResponse` as the parameter `response_class` of your *path operation decorator*. -{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial002_py310.py hl[2,7] *} /// info @@ -73,7 +73,7 @@ As seen in [Return a Response directly](response-directly.md){.internal-link tar The same example from above, returning an `HTMLResponse`, could look like: -{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *} +{* ../../docs_src/custom_response/tutorial003_py310.py hl[2,7,19] *} /// warning @@ -97,7 +97,7 @@ The `response_class` will then be used only to document the OpenAPI *path operat For example, it could be something like: -{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *} +{* ../../docs_src/custom_response/tutorial004_py310.py hl[7,21,23] *} In this example, the function `generate_html_response()` already generates and returns a `Response` instead of returning the HTML in a `str`. @@ -136,7 +136,7 @@ It accepts the following parameters: FastAPI (actually Starlette) will automatically include a Content-Length header. It will also include a Content-Type header, based on the `media_type` and appending a charset for text types. -{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *} +{* ../../docs_src/response_directly/tutorial002_py310.py hl[1,18] *} ### `HTMLResponse` { #htmlresponse } @@ -146,7 +146,7 @@ Takes some text or bytes and returns an HTML response, as you read above. Takes some text or bytes and returns a plain text response. -{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *} +{* ../../docs_src/custom_response/tutorial005_py310.py hl[2,7,9] *} ### `JSONResponse` { #jsonresponse } @@ -180,7 +180,7 @@ This requires installing `ujson` for example with `pip install ujson`. /// -{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial001_py310.py hl[2,7] *} /// tip @@ -194,14 +194,14 @@ Returns an HTTP redirect. Uses a 307 status code (Temporary Redirect) by default You can return a `RedirectResponse` directly: -{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *} +{* ../../docs_src/custom_response/tutorial006_py310.py hl[2,9] *} --- Or you can use it in the `response_class` parameter: -{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *} +{* ../../docs_src/custom_response/tutorial006b_py310.py hl[2,7,9] *} If you do that, then you can return the URL directly from your *path operation* function. @@ -211,13 +211,13 @@ In this case, the `status_code` used will be the default one for the `RedirectRe You can also use the `status_code` parameter combined with the `response_class` parameter: -{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *} +{* ../../docs_src/custom_response/tutorial006c_py310.py hl[2,7,9] *} ### `StreamingResponse` { #streamingresponse } Takes an async generator or a normal generator/iterator and streams the response body. -{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *} +{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *} #### Using `StreamingResponse` with file-like objects { #using-streamingresponse-with-file-like-objects } @@ -227,7 +227,7 @@ That way, you don't have to read it all first in memory, and you can pass that g This includes many libraries to interact with cloud storage, video processing, and others. -{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *} +{* ../../docs_src/custom_response/tutorial008_py310.py hl[2,10:12,14] *} 1. This is the generator function. It's a "generator function" because it contains `yield` statements inside. 2. By using a `with` block, we make sure that the file-like object is closed after the generator function is done. So, after it finishes sending the response. @@ -256,11 +256,11 @@ Takes a different set of arguments to instantiate than the other response types: File responses will include appropriate `Content-Length`, `Last-Modified` and `ETag` headers. -{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *} +{* ../../docs_src/custom_response/tutorial009_py310.py hl[2,10] *} You can also use the `response_class` parameter: -{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *} +{* ../../docs_src/custom_response/tutorial009b_py310.py hl[2,8,10] *} In this case, you can return the file path directly from your *path operation* function. @@ -274,7 +274,7 @@ Let's say you want it to return indented and formatted JSON, so you want to use You could create a `CustomORJSONResponse`. The main thing you have to do is create a `Response.render(content)` method that returns the content as `bytes`: -{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *} +{* ../../docs_src/custom_response/tutorial009c_py310.py hl[9:14,17] *} Now instead of returning: @@ -300,7 +300,7 @@ The parameter that defines this is `default_response_class`. In the example below, **FastAPI** will use `ORJSONResponse` by default, in all *path operations*, instead of `JSONResponse`. -{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *} +{* ../../docs_src/custom_response/tutorial010_py310.py hl[2,4] *} /// tip diff --git a/docs/en/docs/advanced/events.md b/docs/en/docs/advanced/events.md index 9414b7a3f..302e96325 100644 --- a/docs/en/docs/advanced/events.md +++ b/docs/en/docs/advanced/events.md @@ -30,7 +30,7 @@ Let's start with an example and then see it in detail. We create an async function `lifespan()` with `yield` like this: -{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *} +{* ../../docs_src/events/tutorial003_py310.py hl[16,19] *} Here we are simulating the expensive *startup* operation of loading the model by putting the (fake) model function in the dictionary with machine learning models before the `yield`. This code will be executed **before** the application **starts taking requests**, during the *startup*. @@ -48,7 +48,7 @@ Maybe you need to start a new version, or you just got tired of running it. 🤷 The first thing to notice, is that we are defining an async function with `yield`. This is very similar to Dependencies with `yield`. -{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *} +{* ../../docs_src/events/tutorial003_py310.py hl[14:19] *} The first part of the function, before the `yield`, will be executed **before** the application starts. @@ -60,7 +60,7 @@ If you check, the function is decorated with an `@asynccontextmanager`. That converts the function into something called an "**async context manager**". -{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *} +{* ../../docs_src/events/tutorial003_py310.py hl[1,13] *} A **context manager** in Python is something that you can use in a `with` statement, for example, `open()` can be used as a context manager: @@ -82,7 +82,7 @@ In our code example above, we don't use it directly, but we pass it to FastAPI f The `lifespan` parameter of the `FastAPI` app takes an **async context manager**, so we can pass our new `lifespan` async context manager to it. -{* ../../docs_src/events/tutorial003_py39.py hl[22] *} +{* ../../docs_src/events/tutorial003_py310.py hl[22] *} ## Alternative Events (deprecated) { #alternative-events-deprecated } @@ -104,7 +104,7 @@ These functions can be declared with `async def` or normal `def`. To add a function that should be run before the application starts, declare it with the event `"startup"`: -{* ../../docs_src/events/tutorial001_py39.py hl[8] *} +{* ../../docs_src/events/tutorial001_py310.py hl[8] *} In this case, the `startup` event handler function will initialize the items "database" (just a `dict`) with some values. @@ -116,7 +116,7 @@ And your application won't start receiving requests until all the `startup` even To add a function that should be run when the application is shutting down, declare it with the event `"shutdown"`: -{* ../../docs_src/events/tutorial002_py39.py hl[6] *} +{* ../../docs_src/events/tutorial002_py310.py hl[6] *} Here, the `shutdown` event handler function will write a text line `"Application shutdown"` to a file `log.txt`. diff --git a/docs/en/docs/advanced/generate-clients.md b/docs/en/docs/advanced/generate-clients.md index 2d0c2aa0c..1e6173c9a 100644 --- a/docs/en/docs/advanced/generate-clients.md +++ b/docs/en/docs/advanced/generate-clients.md @@ -40,7 +40,7 @@ Some of these solutions may also be open source or offer free tiers, so you can Let's start with a simple FastAPI application: -{* ../../docs_src/generate_clients/tutorial001_py39.py hl[7:9,12:13,16:17,21] *} +{* ../../docs_src/generate_clients/tutorial001_py310.py hl[7:9,12:13,16:17,21] *} Notice that the *path operations* define the models they use for request payload and response payload, using the models `Item` and `ResponseMessage`. @@ -98,7 +98,7 @@ In many cases, your FastAPI app will be bigger, and you will probably use tags t For example, you could have a section for **items** and another section for **users**, and they could be separated by tags: -{* ../../docs_src/generate_clients/tutorial002_py39.py hl[21,26,34] *} +{* ../../docs_src/generate_clients/tutorial002_py310.py hl[21,26,34] *} ### Generate a TypeScript Client with Tags { #generate-a-typescript-client-with-tags } @@ -145,7 +145,7 @@ For example, here it is using the first tag (you will probably have only one tag You can then pass that custom function to **FastAPI** as the `generate_unique_id_function` parameter: -{* ../../docs_src/generate_clients/tutorial003_py39.py hl[6:7,10] *} +{* ../../docs_src/generate_clients/tutorial003_py310.py hl[6:7,10] *} ### Generate a TypeScript Client with Custom Operation IDs { #generate-a-typescript-client-with-custom-operation-ids } @@ -167,7 +167,7 @@ But for the generated client, we could **modify** the OpenAPI operation IDs righ We could download the OpenAPI JSON to a file `openapi.json` and then we could **remove that prefixed tag** with a script like this: -{* ../../docs_src/generate_clients/tutorial004_py39.py *} +{* ../../docs_src/generate_clients/tutorial004_py310.py *} //// tab | Node.js diff --git a/docs/en/docs/advanced/middleware.md b/docs/en/docs/advanced/middleware.md index 765b38932..b448f5c52 100644 --- a/docs/en/docs/advanced/middleware.md +++ b/docs/en/docs/advanced/middleware.md @@ -57,13 +57,13 @@ Enforces that all incoming requests must either be `https` or `wss`. Any incoming request to `http` or `ws` will be redirected to the secure scheme instead. -{* ../../docs_src/advanced_middleware/tutorial001_py39.py hl[2,6] *} +{* ../../docs_src/advanced_middleware/tutorial001_py310.py hl[2,6] *} ## `TrustedHostMiddleware` { #trustedhostmiddleware } Enforces that all incoming requests have a correctly set `Host` header, in order to guard against HTTP Host Header attacks. -{* ../../docs_src/advanced_middleware/tutorial002_py39.py hl[2,6:8] *} +{* ../../docs_src/advanced_middleware/tutorial002_py310.py hl[2,6:8] *} The following arguments are supported: @@ -78,7 +78,7 @@ Handles GZip responses for any request that includes `"gzip"` in the `Accept-Enc The middleware will handle both standard and streaming responses. -{* ../../docs_src/advanced_middleware/tutorial003_py39.py hl[2,6] *} +{* ../../docs_src/advanced_middleware/tutorial003_py310.py hl[2,6] *} The following arguments are supported: diff --git a/docs/en/docs/advanced/openapi-webhooks.md b/docs/en/docs/advanced/openapi-webhooks.md index 59f060c03..f4f586f84 100644 --- a/docs/en/docs/advanced/openapi-webhooks.md +++ b/docs/en/docs/advanced/openapi-webhooks.md @@ -32,7 +32,7 @@ Webhooks are available in OpenAPI 3.1.0 and above, supported by FastAPI `0.99.0` When you create a **FastAPI** application, there is a `webhooks` attribute that you can use to define *webhooks*, the same way you would define *path operations*, for example with `@app.webhooks.post()`. -{* ../../docs_src/openapi_webhooks/tutorial001_py39.py hl[9:13,36:53] *} +{* ../../docs_src/openapi_webhooks/tutorial001_py310.py hl[9:13,36:53] *} The webhooks that you define will end up in the **OpenAPI** schema and the automatic **docs UI**. diff --git a/docs/en/docs/advanced/path-operation-advanced-configuration.md b/docs/en/docs/advanced/path-operation-advanced-configuration.md index 3d7bfdee5..fdc77c8a2 100644 --- a/docs/en/docs/advanced/path-operation-advanced-configuration.md +++ b/docs/en/docs/advanced/path-operation-advanced-configuration.md @@ -12,7 +12,7 @@ You can set the OpenAPI `operationId` to be used in your *path operation* with t You would have to make sure that it is unique for each operation. -{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py310.py hl[6] *} ### Using the *path operation function* name as the operationId { #using-the-path-operation-function-name-as-the-operationid } @@ -20,7 +20,7 @@ If you want to use your APIs' function names as `operationId`s, you can iterate You should do it after adding all your *path operations*. -{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py310.py hl[2, 12:21, 24] *} /// tip @@ -40,7 +40,7 @@ Even if they are in different modules (Python files). To exclude a *path operation* from the generated OpenAPI schema (and thus, from the automatic documentation systems), use the parameter `include_in_schema` and set it to `False`: -{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py310.py hl[6] *} ## Advanced description from docstring { #advanced-description-from-docstring } @@ -92,7 +92,7 @@ You can extend the OpenAPI schema for a *path operation* using the parameter `op This `openapi_extra` can be helpful, for example, to declare [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions): -{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py310.py hl[6] *} If you open the automatic API docs, your extension will show up at the bottom of the specific *path operation*. @@ -139,7 +139,7 @@ For example, you could decide to read and validate the request with your own cod You could do that with `openapi_extra`: -{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py310.py hl[19:36, 39:40] *} In this example, we didn't declare any Pydantic model. In fact, the request body is not even parsed as JSON, it is read directly as `bytes`, and the function `magic_data_reader()` would be in charge of parsing it in some way. @@ -153,7 +153,7 @@ And you could do this even if the data type in the request is not JSON. For example, in this application we don't use FastAPI's integrated functionality to extract the JSON Schema from Pydantic models nor the automatic validation for JSON. In fact, we are declaring the request content type as YAML, not JSON: -{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[15:20, 22] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[15:20, 22] *} Nevertheless, although we are not using the default integrated functionality, we are still using a Pydantic model to manually generate the JSON Schema for the data that we want to receive in YAML. @@ -161,7 +161,7 @@ Then we use the request directly, and extract the body as `bytes`. This means th And then in our code, we parse that YAML content directly, and then we are again using the same Pydantic model to validate the YAML content: -{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py39.py hl[24:31] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial007_py310.py hl[24:31] *} /// tip diff --git a/docs/en/docs/advanced/response-change-status-code.md b/docs/en/docs/advanced/response-change-status-code.md index d9708aa62..8aa601e7b 100644 --- a/docs/en/docs/advanced/response-change-status-code.md +++ b/docs/en/docs/advanced/response-change-status-code.md @@ -20,7 +20,7 @@ You can declare a parameter of type `Response` in your *path operation function* And then you can set the `status_code` in that *temporal* response object. -{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *} +{* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *} And then you can return any object you need, as you normally would (a `dict`, a database model, etc). diff --git a/docs/en/docs/advanced/response-cookies.md b/docs/en/docs/advanced/response-cookies.md index 5b6fab112..cfc615d7e 100644 --- a/docs/en/docs/advanced/response-cookies.md +++ b/docs/en/docs/advanced/response-cookies.md @@ -6,7 +6,7 @@ You can declare a parameter of type `Response` in your *path operation function* And then you can set cookies in that *temporal* response object. -{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *} +{* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *} And then you can return any object you need, as you normally would (a `dict`, a database model, etc). @@ -24,7 +24,7 @@ To do that, you can create a response as described in [Return a Response Directl Then set Cookies in it, and then return it: -{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *} +{* ../../docs_src/response_cookies/tutorial001_py310.py hl[10:12] *} /// tip diff --git a/docs/en/docs/advanced/response-directly.md b/docs/en/docs/advanced/response-directly.md index 4374cb963..76cc50d03 100644 --- a/docs/en/docs/advanced/response-directly.md +++ b/docs/en/docs/advanced/response-directly.md @@ -54,7 +54,7 @@ Let's say that you want to return an Strawberry documentation. diff --git a/docs/en/docs/python-types.md b/docs/en/docs/python-types.md index f2ad35d71..90c32cec8 100644 --- a/docs/en/docs/python-types.md +++ b/docs/en/docs/python-types.md @@ -22,7 +22,7 @@ If you are a Python expert, and you already know everything about type hints, sk Let's start with a simple example: -{* ../../docs_src/python_types/tutorial001_py39.py *} +{* ../../docs_src/python_types/tutorial001_py310.py *} Calling this program outputs: @@ -36,7 +36,7 @@ The function does the following: * Converts the first letter of each one to upper case with `title()`. * Concatenates them with a space in the middle. -{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *} +{* ../../docs_src/python_types/tutorial001_py310.py hl[2] *} ### Edit it { #edit-it } @@ -78,7 +78,7 @@ That's it. Those are the "type hints": -{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial002_py310.py hl[1] *} That is not the same as declaring default values like would be with: @@ -106,7 +106,7 @@ With that, you can scroll, seeing the options, until you find the one that "ring Check this function, it already has type hints: -{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial003_py310.py hl[1] *} Because the editor knows the types of the variables, you don't only get completion, you also get error checks: @@ -114,7 +114,7 @@ Because the editor knows the types of the variables, you don't only get completi Now you know that you have to fix it, convert `age` to a string with `str(age)`: -{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *} +{* ../../docs_src/python_types/tutorial004_py310.py hl[2] *} ## Declaring types { #declaring-types } @@ -133,7 +133,7 @@ You can use, for example: * `bool` * `bytes` -{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial005_py310.py hl[1] *} ### `typing` module { #typing-module } @@ -170,7 +170,7 @@ As the type, put `list`. As the list is a type that contains some internal types, you put them in square brackets: -{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial006_py310.py hl[1] *} /// info @@ -196,7 +196,7 @@ And still, the editor knows it is a `str`, and provides support for that. You would do the same to declare `tuple`s and `set`s: -{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial007_py310.py hl[1] *} This means: @@ -211,7 +211,7 @@ The first type parameter is for the keys of the `dict`. The second type parameter is for the values of the `dict`: -{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *} +{* ../../docs_src/python_types/tutorial008_py310.py hl[1] *} This means: @@ -253,11 +253,11 @@ You can also declare a class as the type of a variable. Let's say you have a class `Person`, with a name: -{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *} +{* ../../docs_src/python_types/tutorial010_py310.py hl[1:3] *} Then you can declare a variable to be of type `Person`: -{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *} +{* ../../docs_src/python_types/tutorial010_py310.py hl[6] *} And then, again, you get all the editor support: @@ -299,7 +299,7 @@ Python also has a feature that allows putting **additional deprecated, but without removing it, pass the parameter `deprecated`: -{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *} +{* ../../docs_src/path_operation_configuration/tutorial006_py310.py hl[16] *} It will be clearly marked as deprecated in the interactive docs: diff --git a/docs/en/docs/tutorial/path-params-numeric-validations.md b/docs/en/docs/tutorial/path-params-numeric-validations.md index 8b1b8a839..de63a51f5 100644 --- a/docs/en/docs/tutorial/path-params-numeric-validations.md +++ b/docs/en/docs/tutorial/path-params-numeric-validations.md @@ -54,11 +54,11 @@ It doesn't matter for **FastAPI**. It will detect the parameters by their names, So, you can declare your function as: -{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial002_py310.py hl[7] *} But keep in mind that if you use `Annotated`, you won't have this problem, it won't matter as you're not using the function parameter default values for `Query()` or `Path()`. -{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py39.py *} +{* ../../docs_src/path_params_numeric_validations/tutorial002_an_py310.py *} ## Order the parameters as you need, tricks { #order-the-parameters-as-you-need-tricks } @@ -83,13 +83,13 @@ Pass `*`, as the first parameter of the function. Python won't do anything with that `*`, but it will know that all the following parameters should be called as keyword arguments (key-value pairs), also known as kwargs. Even if they don't have a default value. -{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial003_py310.py hl[7] *} ### Better with `Annotated` { #better-with-annotated } Keep in mind that if you use `Annotated`, as you are not using function parameter default values, you won't have this problem, and you probably won't need to use `*`. -{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py39.py hl[10] *} +{* ../../docs_src/path_params_numeric_validations/tutorial003_an_py310.py hl[10] *} ## Number validations: greater than or equal { #number-validations-greater-than-or-equal } @@ -97,7 +97,7 @@ With `Query` and `Path` (and others you'll see later) you can declare number con Here, with `ge=1`, `item_id` will need to be an integer number "`g`reater than or `e`qual" to `1`. -{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py39.py hl[10] *} +{* ../../docs_src/path_params_numeric_validations/tutorial004_an_py310.py hl[10] *} ## Number validations: greater than and less than or equal { #number-validations-greater-than-and-less-than-or-equal } @@ -106,7 +106,7 @@ The same applies for: * `gt`: `g`reater `t`han * `le`: `l`ess than or `e`qual -{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py39.py hl[10] *} +{* ../../docs_src/path_params_numeric_validations/tutorial005_an_py310.py hl[10] *} ## Number validations: floats, greater than and less than { #number-validations-floats-greater-than-and-less-than } @@ -118,7 +118,7 @@ So, `0.5` would be a valid value. But `0.0` or `0` would not. And the same for lt. -{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py39.py hl[13] *} +{* ../../docs_src/path_params_numeric_validations/tutorial006_an_py310.py hl[13] *} ## Recap { #recap } diff --git a/docs/en/docs/tutorial/path-params.md b/docs/en/docs/tutorial/path-params.md index cf312f1fe..8adbbcfa1 100644 --- a/docs/en/docs/tutorial/path-params.md +++ b/docs/en/docs/tutorial/path-params.md @@ -2,7 +2,7 @@ You can declare path "parameters" or "variables" with the same syntax used by Python format strings: -{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *} +{* ../../docs_src/path_params/tutorial001_py310.py hl[6:7] *} The value of the path parameter `item_id` will be passed to your function as the argument `item_id`. @@ -16,7 +16,7 @@ So, if you run this example and go to Item: - if x_token != fake_secret_token: - raise HTTPException(status_code=400, detail="Invalid X-Token header") - if item.id in fake_db: - raise HTTPException(status_code=409, detail="Item already exists") - fake_db[item.id] = item.model_dump() - return item diff --git a/docs_src/app_testing/app_b_an_py39/test_main.py b/docs_src/app_testing/app_b_an_py39/test_main.py deleted file mode 100644 index 4e1c51ecc..000000000 --- a/docs_src/app_testing/app_b_an_py39/test_main.py +++ /dev/null @@ -1,65 +0,0 @@ -from fastapi.testclient import TestClient - -from .main import app - -client = TestClient(app) - - -def test_read_item(): - response = client.get("/items/foo", headers={"X-Token": "coneofsilence"}) - assert response.status_code == 200 - assert response.json() == { - "id": "foo", - "title": "Foo", - "description": "There goes my hero", - } - - -def test_read_item_bad_token(): - response = client.get("/items/foo", headers={"X-Token": "hailhydra"}) - assert response.status_code == 400 - assert response.json() == {"detail": "Invalid X-Token header"} - - -def test_read_nonexistent_item(): - response = client.get("/items/baz", headers={"X-Token": "coneofsilence"}) - assert response.status_code == 404 - assert response.json() == {"detail": "Item not found"} - - -def test_create_item(): - response = client.post( - "/items/", - headers={"X-Token": "coneofsilence"}, - json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"}, - ) - assert response.status_code == 200 - assert response.json() == { - "id": "foobar", - "title": "Foo Bar", - "description": "The Foo Barters", - } - - -def test_create_item_bad_token(): - response = client.post( - "/items/", - headers={"X-Token": "hailhydra"}, - json={"id": "bazz", "title": "Bazz", "description": "Drop the bazz"}, - ) - assert response.status_code == 400 - assert response.json() == {"detail": "Invalid X-Token header"} - - -def test_create_existing_item(): - response = client.post( - "/items/", - headers={"X-Token": "coneofsilence"}, - json={ - "id": "foo", - "title": "The Foo ID Stealers", - "description": "There goes my stealer", - }, - ) - assert response.status_code == 409 - assert response.json() == {"detail": "Item already exists"} diff --git a/docs_src/app_testing/app_b_py39/main.py b/docs_src/app_testing/app_b_py39/main.py deleted file mode 100644 index ed38f4721..000000000 --- a/docs_src/app_testing/app_b_py39/main.py +++ /dev/null @@ -1,38 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header, HTTPException -from pydantic import BaseModel - -fake_secret_token = "coneofsilence" - -fake_db = { - "foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"}, - "bar": {"id": "bar", "title": "Bar", "description": "The bartenders"}, -} - -app = FastAPI() - - -class Item(BaseModel): - id: str - title: str - description: Union[str, None] = None - - -@app.get("/items/{item_id}", response_model=Item) -async def read_main(item_id: str, x_token: str = Header()): - if x_token != fake_secret_token: - raise HTTPException(status_code=400, detail="Invalid X-Token header") - if item_id not in fake_db: - raise HTTPException(status_code=404, detail="Item not found") - return fake_db[item_id] - - -@app.post("/items/") -async def create_item(item: Item, x_token: str = Header()) -> Item: - if x_token != fake_secret_token: - raise HTTPException(status_code=400, detail="Invalid X-Token header") - if item.id in fake_db: - raise HTTPException(status_code=409, detail="Item already exists") - fake_db[item.id] = item.model_dump() - return item diff --git a/docs_src/app_testing/app_b_py39/test_main.py b/docs_src/app_testing/app_b_py39/test_main.py deleted file mode 100644 index 4e1c51ecc..000000000 --- a/docs_src/app_testing/app_b_py39/test_main.py +++ /dev/null @@ -1,65 +0,0 @@ -from fastapi.testclient import TestClient - -from .main import app - -client = TestClient(app) - - -def test_read_item(): - response = client.get("/items/foo", headers={"X-Token": "coneofsilence"}) - assert response.status_code == 200 - assert response.json() == { - "id": "foo", - "title": "Foo", - "description": "There goes my hero", - } - - -def test_read_item_bad_token(): - response = client.get("/items/foo", headers={"X-Token": "hailhydra"}) - assert response.status_code == 400 - assert response.json() == {"detail": "Invalid X-Token header"} - - -def test_read_nonexistent_item(): - response = client.get("/items/baz", headers={"X-Token": "coneofsilence"}) - assert response.status_code == 404 - assert response.json() == {"detail": "Item not found"} - - -def test_create_item(): - response = client.post( - "/items/", - headers={"X-Token": "coneofsilence"}, - json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"}, - ) - assert response.status_code == 200 - assert response.json() == { - "id": "foobar", - "title": "Foo Bar", - "description": "The Foo Barters", - } - - -def test_create_item_bad_token(): - response = client.post( - "/items/", - headers={"X-Token": "hailhydra"}, - json={"id": "bazz", "title": "Bazz", "description": "Drop the bazz"}, - ) - assert response.status_code == 400 - assert response.json() == {"detail": "Invalid X-Token header"} - - -def test_create_existing_item(): - response = client.post( - "/items/", - headers={"X-Token": "coneofsilence"}, - json={ - "id": "foo", - "title": "The Foo ID Stealers", - "description": "There goes my stealer", - }, - ) - assert response.status_code == 409 - assert response.json() == {"detail": "Item already exists"} diff --git a/docs_src/app_testing/tutorial001_py310.py b/docs_src/app_testing/tutorial001_py310.py new file mode 100644 index 000000000..79a853b48 --- /dev/null +++ b/docs_src/app_testing/tutorial001_py310.py @@ -0,0 +1,18 @@ +from fastapi import FastAPI +from fastapi.testclient import TestClient + +app = FastAPI() + + +@app.get("/") +async def read_main(): + return {"msg": "Hello World"} + + +client = TestClient(app) + + +def test_read_main(): + response = client.get("/") + assert response.status_code == 200 + assert response.json() == {"msg": "Hello World"} diff --git a/docs_src/app_testing/tutorial002_py310.py b/docs_src/app_testing/tutorial002_py310.py new file mode 100644 index 000000000..71c898b3c --- /dev/null +++ b/docs_src/app_testing/tutorial002_py310.py @@ -0,0 +1,31 @@ +from fastapi import FastAPI +from fastapi.testclient import TestClient +from fastapi.websockets import WebSocket + +app = FastAPI() + + +@app.get("/") +async def read_main(): + return {"msg": "Hello World"} + + +@app.websocket("/ws") +async def websocket(websocket: WebSocket): + await websocket.accept() + await websocket.send_json({"msg": "Hello WebSocket"}) + await websocket.close() + + +def test_read_main(): + client = TestClient(app) + response = client.get("/") + assert response.status_code == 200 + assert response.json() == {"msg": "Hello World"} + + +def test_websocket(): + client = TestClient(app) + with client.websocket_connect("/ws") as websocket: + data = websocket.receive_json() + assert data == {"msg": "Hello WebSocket"} diff --git a/docs_src/app_testing/tutorial003_py310.py b/docs_src/app_testing/tutorial003_py310.py new file mode 100644 index 000000000..ca6b45ce0 --- /dev/null +++ b/docs_src/app_testing/tutorial003_py310.py @@ -0,0 +1,24 @@ +from fastapi import FastAPI +from fastapi.testclient import TestClient + +app = FastAPI() + +items = {} + + +@app.on_event("startup") +async def startup_event(): + items["foo"] = {"name": "Fighters"} + items["bar"] = {"name": "Tenders"} + + +@app.get("/items/{item_id}") +async def read_items(item_id: str): + return items[item_id] + + +def test_read_items(): + with TestClient(app) as client: + response = client.get("/items/foo") + assert response.status_code == 200 + assert response.json() == {"name": "Fighters"} diff --git a/docs_src/app_testing/tutorial004_py310.py b/docs_src/app_testing/tutorial004_py310.py new file mode 100644 index 000000000..f83ac9ae9 --- /dev/null +++ b/docs_src/app_testing/tutorial004_py310.py @@ -0,0 +1,43 @@ +from contextlib import asynccontextmanager + +from fastapi import FastAPI +from fastapi.testclient import TestClient + +items = {} + + +@asynccontextmanager +async def lifespan(app: FastAPI): + items["foo"] = {"name": "Fighters"} + items["bar"] = {"name": "Tenders"} + yield + # clean up items + items.clear() + + +app = FastAPI(lifespan=lifespan) + + +@app.get("/items/{item_id}") +async def read_items(item_id: str): + return items[item_id] + + +def test_read_items(): + # Before the lifespan starts, "items" is still empty + assert items == {} + + with TestClient(app) as client: + # Inside the "with TestClient" block, the lifespan starts and items added + assert items == {"foo": {"name": "Fighters"}, "bar": {"name": "Tenders"}} + + response = client.get("/items/foo") + assert response.status_code == 200 + assert response.json() == {"name": "Fighters"} + + # After the requests is done, the items are still there + assert items == {"foo": {"name": "Fighters"}, "bar": {"name": "Tenders"}} + + # The end of the "with TestClient" block simulates terminating the app, so + # the lifespan ends and items are cleaned up + assert items == {} diff --git a/docs_src/async_tests/app_a_py310/__init__.py b/docs_src/async_tests/app_a_py310/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/async_tests/app_a_py310/main.py b/docs_src/async_tests/app_a_py310/main.py new file mode 100644 index 000000000..9594f859c --- /dev/null +++ b/docs_src/async_tests/app_a_py310/main.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +async def root(): + return {"message": "Tomato"} diff --git a/docs_src/async_tests/app_a_py310/test_main.py b/docs_src/async_tests/app_a_py310/test_main.py new file mode 100644 index 000000000..a57a31f7d --- /dev/null +++ b/docs_src/async_tests/app_a_py310/test_main.py @@ -0,0 +1,14 @@ +import pytest +from httpx import ASGITransport, AsyncClient + +from .main import app + + +@pytest.mark.anyio +async def test_root(): + async with AsyncClient( + transport=ASGITransport(app=app), base_url="http://test" + ) as ac: + response = await ac.get("/") + assert response.status_code == 200 + assert response.json() == {"message": "Tomato"} diff --git a/docs_src/authentication_error_status_code/tutorial001_an_py310.py b/docs_src/authentication_error_status_code/tutorial001_an_py310.py new file mode 100644 index 000000000..7bbc2f717 --- /dev/null +++ b/docs_src/authentication_error_status_code/tutorial001_an_py310.py @@ -0,0 +1,21 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI, HTTPException, status +from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer + +app = FastAPI() + + +class HTTPBearer403(HTTPBearer): + def make_not_authenticated_error(self) -> HTTPException: + return HTTPException( + status_code=status.HTTP_403_FORBIDDEN, detail="Not authenticated" + ) + + +CredentialsDep = Annotated[HTTPAuthorizationCredentials, Depends(HTTPBearer403())] + + +@app.get("/me") +def read_me(credentials: CredentialsDep): + return {"message": "You are authenticated", "token": credentials.credentials} diff --git a/docs_src/background_tasks/tutorial001_py310.py b/docs_src/background_tasks/tutorial001_py310.py new file mode 100644 index 000000000..1720a7433 --- /dev/null +++ b/docs_src/background_tasks/tutorial001_py310.py @@ -0,0 +1,15 @@ +from fastapi import BackgroundTasks, FastAPI + +app = FastAPI() + + +def write_notification(email: str, message=""): + with open("log.txt", mode="w") as email_file: + content = f"notification for {email}: {message}" + email_file.write(content) + + +@app.post("/send-notification/{email}") +async def send_notification(email: str, background_tasks: BackgroundTasks): + background_tasks.add_task(write_notification, email, message="some notification") + return {"message": "Notification sent in the background"} diff --git a/docs_src/background_tasks/tutorial002_an_py39.py b/docs_src/background_tasks/tutorial002_an_py39.py deleted file mode 100644 index bfdd14875..000000000 --- a/docs_src/background_tasks/tutorial002_an_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Annotated, Union - -from fastapi import BackgroundTasks, Depends, FastAPI - -app = FastAPI() - - -def write_log(message: str): - with open("log.txt", mode="a") as log: - log.write(message) - - -def get_query(background_tasks: BackgroundTasks, q: Union[str, None] = None): - if q: - message = f"found query: {q}\n" - background_tasks.add_task(write_log, message) - return q - - -@app.post("/send-notification/{email}") -async def send_notification( - email: str, background_tasks: BackgroundTasks, q: Annotated[str, Depends(get_query)] -): - message = f"message to {email}\n" - background_tasks.add_task(write_log, message) - return {"message": "Message sent"} diff --git a/docs_src/background_tasks/tutorial002_py39.py b/docs_src/background_tasks/tutorial002_py39.py deleted file mode 100644 index 2e1b2f6c6..000000000 --- a/docs_src/background_tasks/tutorial002_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union - -from fastapi import BackgroundTasks, Depends, FastAPI - -app = FastAPI() - - -def write_log(message: str): - with open("log.txt", mode="a") as log: - log.write(message) - - -def get_query(background_tasks: BackgroundTasks, q: Union[str, None] = None): - if q: - message = f"found query: {q}\n" - background_tasks.add_task(write_log, message) - return q - - -@app.post("/send-notification/{email}") -async def send_notification( - email: str, background_tasks: BackgroundTasks, q: str = Depends(get_query) -): - message = f"message to {email}\n" - background_tasks.add_task(write_log, message) - return {"message": "Message sent"} diff --git a/docs_src/behind_a_proxy/tutorial001_01_py310.py b/docs_src/behind_a_proxy/tutorial001_01_py310.py new file mode 100644 index 000000000..52b114395 --- /dev/null +++ b/docs_src/behind_a_proxy/tutorial001_01_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/") +def read_items(): + return ["plumbus", "portal gun"] diff --git a/docs_src/behind_a_proxy/tutorial001_py310.py b/docs_src/behind_a_proxy/tutorial001_py310.py new file mode 100644 index 000000000..ede59ada1 --- /dev/null +++ b/docs_src/behind_a_proxy/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI, Request + +app = FastAPI() + + +@app.get("/app") +def read_main(request: Request): + return {"message": "Hello World", "root_path": request.scope.get("root_path")} diff --git a/docs_src/behind_a_proxy/tutorial002_py310.py b/docs_src/behind_a_proxy/tutorial002_py310.py new file mode 100644 index 000000000..c1600cde9 --- /dev/null +++ b/docs_src/behind_a_proxy/tutorial002_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI, Request + +app = FastAPI(root_path="/api/v1") + + +@app.get("/app") +def read_main(request: Request): + return {"message": "Hello World", "root_path": request.scope.get("root_path")} diff --git a/docs_src/behind_a_proxy/tutorial003_py310.py b/docs_src/behind_a_proxy/tutorial003_py310.py new file mode 100644 index 000000000..3b7d8be01 --- /dev/null +++ b/docs_src/behind_a_proxy/tutorial003_py310.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI, Request + +app = FastAPI( + servers=[ + {"url": "https://stag.example.com", "description": "Staging environment"}, + {"url": "https://prod.example.com", "description": "Production environment"}, + ], + root_path="/api/v1", +) + + +@app.get("/app") +def read_main(request: Request): + return {"message": "Hello World", "root_path": request.scope.get("root_path")} diff --git a/docs_src/behind_a_proxy/tutorial004_py310.py b/docs_src/behind_a_proxy/tutorial004_py310.py new file mode 100644 index 000000000..51bd5babc --- /dev/null +++ b/docs_src/behind_a_proxy/tutorial004_py310.py @@ -0,0 +1,15 @@ +from fastapi import FastAPI, Request + +app = FastAPI( + servers=[ + {"url": "https://stag.example.com", "description": "Staging environment"}, + {"url": "https://prod.example.com", "description": "Production environment"}, + ], + root_path="/api/v1", + root_path_in_servers=False, +) + + +@app.get("/app") +def read_main(request: Request): + return {"message": "Hello World", "root_path": request.scope.get("root_path")} diff --git a/docs_src/bigger_applications/app_an_py310/__init__.py b/docs_src/bigger_applications/app_an_py310/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/bigger_applications/app_an_py310/dependencies.py b/docs_src/bigger_applications/app_an_py310/dependencies.py new file mode 100644 index 000000000..5c7612aa0 --- /dev/null +++ b/docs_src/bigger_applications/app_an_py310/dependencies.py @@ -0,0 +1,13 @@ +from typing import Annotated + +from fastapi import Header, HTTPException + + +async def get_token_header(x_token: Annotated[str, Header()]): + if x_token != "fake-super-secret-token": + raise HTTPException(status_code=400, detail="X-Token header invalid") + + +async def get_query_token(token: str): + if token != "jessica": + raise HTTPException(status_code=400, detail="No Jessica token provided") diff --git a/docs_src/bigger_applications/app_an_py310/internal/__init__.py b/docs_src/bigger_applications/app_an_py310/internal/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/bigger_applications/app_py39/internal/admin.py b/docs_src/bigger_applications/app_an_py310/internal/admin.py similarity index 100% rename from docs_src/bigger_applications/app_py39/internal/admin.py rename to docs_src/bigger_applications/app_an_py310/internal/admin.py diff --git a/docs_src/bigger_applications/app_an_py310/main.py b/docs_src/bigger_applications/app_an_py310/main.py new file mode 100644 index 000000000..ae544a3aa --- /dev/null +++ b/docs_src/bigger_applications/app_an_py310/main.py @@ -0,0 +1,23 @@ +from fastapi import Depends, FastAPI + +from .dependencies import get_query_token, get_token_header +from .internal import admin +from .routers import items, users + +app = FastAPI(dependencies=[Depends(get_query_token)]) + + +app.include_router(users.router) +app.include_router(items.router) +app.include_router( + admin.router, + prefix="/admin", + tags=["admin"], + dependencies=[Depends(get_token_header)], + responses={418: {"description": "I'm a teapot"}}, +) + + +@app.get("/") +async def root(): + return {"message": "Hello Bigger Applications!"} diff --git a/docs_src/bigger_applications/app_an_py310/routers/__init__.py b/docs_src/bigger_applications/app_an_py310/routers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/bigger_applications/app_py39/routers/items.py b/docs_src/bigger_applications/app_an_py310/routers/items.py similarity index 100% rename from docs_src/bigger_applications/app_py39/routers/items.py rename to docs_src/bigger_applications/app_an_py310/routers/items.py diff --git a/docs_src/bigger_applications/app_py39/routers/users.py b/docs_src/bigger_applications/app_an_py310/routers/users.py similarity index 100% rename from docs_src/bigger_applications/app_py39/routers/users.py rename to docs_src/bigger_applications/app_an_py310/routers/users.py diff --git a/docs_src/bigger_applications/app_py310/__init__.py b/docs_src/bigger_applications/app_py310/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/bigger_applications/app_py310/dependencies.py b/docs_src/bigger_applications/app_py310/dependencies.py new file mode 100644 index 000000000..8e45f004b --- /dev/null +++ b/docs_src/bigger_applications/app_py310/dependencies.py @@ -0,0 +1,11 @@ +from fastapi import Header, HTTPException + + +async def get_token_header(x_token: str = Header()): + if x_token != "fake-super-secret-token": + raise HTTPException(status_code=400, detail="X-Token header invalid") + + +async def get_query_token(token: str): + if token != "jessica": + raise HTTPException(status_code=400, detail="No Jessica token provided") diff --git a/docs_src/bigger_applications/app_py310/internal/__init__.py b/docs_src/bigger_applications/app_py310/internal/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/bigger_applications/app_py310/main.py b/docs_src/bigger_applications/app_py310/main.py new file mode 100644 index 000000000..ae544a3aa --- /dev/null +++ b/docs_src/bigger_applications/app_py310/main.py @@ -0,0 +1,23 @@ +from fastapi import Depends, FastAPI + +from .dependencies import get_query_token, get_token_header +from .internal import admin +from .routers import items, users + +app = FastAPI(dependencies=[Depends(get_query_token)]) + + +app.include_router(users.router) +app.include_router(items.router) +app.include_router( + admin.router, + prefix="/admin", + tags=["admin"], + dependencies=[Depends(get_token_header)], + responses={418: {"description": "I'm a teapot"}}, +) + + +@app.get("/") +async def root(): + return {"message": "Hello Bigger Applications!"} diff --git a/docs_src/bigger_applications/app_py310/routers/__init__.py b/docs_src/bigger_applications/app_py310/routers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/body/tutorial001_py39.py b/docs_src/body/tutorial001_py39.py deleted file mode 100644 index f93317274..000000000 --- a/docs_src/body/tutorial001_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -app = FastAPI() - - -@app.post("/items/") -async def create_item(item: Item): - return item diff --git a/docs_src/body/tutorial002_py39.py b/docs_src/body/tutorial002_py39.py deleted file mode 100644 index fb212e8e7..000000000 --- a/docs_src/body/tutorial002_py39.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -app = FastAPI() - - -@app.post("/items/") -async def create_item(item: Item): - item_dict = item.model_dump() - if item.tax is not None: - price_with_tax = item.price + item.tax - item_dict.update({"price_with_tax": price_with_tax}) - return item_dict diff --git a/docs_src/body/tutorial003_py39.py b/docs_src/body/tutorial003_py39.py deleted file mode 100644 index 636ba2275..000000000 --- a/docs_src/body/tutorial003_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -app = FastAPI() - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - return {"item_id": item_id, **item.model_dump()} diff --git a/docs_src/body/tutorial004_py39.py b/docs_src/body/tutorial004_py39.py deleted file mode 100644 index 2c157abfa..000000000 --- a/docs_src/body/tutorial004_py39.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -app = FastAPI() - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item, q: Union[str, None] = None): - result = {"item_id": item_id, **item.model_dump()} - if q: - result.update({"q": q}) - return result diff --git a/docs_src/body_fields/tutorial001_an_py39.py b/docs_src/body_fields/tutorial001_an_py39.py deleted file mode 100644 index 6ef14470c..000000000 --- a/docs_src/body_fields/tutorial001_an_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel, Field - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = Field( - default=None, title="The description of the item", max_length=300 - ) - price: float = Field(gt=0, description="The price must be greater than zero") - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_fields/tutorial001_py39.py b/docs_src/body_fields/tutorial001_py39.py deleted file mode 100644 index cbeebd614..000000000 --- a/docs_src/body_fields/tutorial001_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel, Field - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = Field( - default=None, title="The description of the item", max_length=300 - ) - price: float = Field(gt=0, description="The price must be greater than zero") - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item = Body(embed=True)): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_multiple_params/tutorial001_an_py39.py b/docs_src/body_multiple_params/tutorial001_an_py39.py deleted file mode 100644 index 1c0ac3a7b..000000000 --- a/docs_src/body_multiple_params/tutorial001_an_py39.py +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Path -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)], - q: Union[str, None] = None, - item: Union[Item, None] = None, -): - results = {"item_id": item_id} - if q: - results.update({"q": q}) - if item: - results.update({"item": item}) - return results diff --git a/docs_src/body_multiple_params/tutorial001_py39.py b/docs_src/body_multiple_params/tutorial001_py39.py deleted file mode 100644 index a73975b3a..000000000 --- a/docs_src/body_multiple_params/tutorial001_py39.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Path -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int = Path(title="The ID of the item to get", ge=0, le=1000), - q: Union[str, None] = None, - item: Union[Item, None] = None, -): - results = {"item_id": item_id} - if q: - results.update({"q": q}) - if item: - results.update({"item": item}) - return results diff --git a/docs_src/body_multiple_params/tutorial002_py39.py b/docs_src/body_multiple_params/tutorial002_py39.py deleted file mode 100644 index 2d7160ae8..000000000 --- a/docs_src/body_multiple_params/tutorial002_py39.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -class User(BaseModel): - username: str - full_name: Union[str, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item, user: User): - results = {"item_id": item_id, "item": item, "user": user} - return results diff --git a/docs_src/body_multiple_params/tutorial003_an_py39.py b/docs_src/body_multiple_params/tutorial003_an_py39.py deleted file mode 100644 index 042351e0b..000000000 --- a/docs_src/body_multiple_params/tutorial003_an_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -class User(BaseModel): - username: str - full_name: Union[str, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - item_id: int, item: Item, user: User, importance: Annotated[int, Body()] -): - results = {"item_id": item_id, "item": item, "user": user, "importance": importance} - return results diff --git a/docs_src/body_multiple_params/tutorial003_py39.py b/docs_src/body_multiple_params/tutorial003_py39.py deleted file mode 100644 index cf344e6c5..000000000 --- a/docs_src/body_multiple_params/tutorial003_py39.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -class User(BaseModel): - username: str - full_name: Union[str, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item, user: User, importance: int = Body()): - results = {"item_id": item_id, "item": item, "user": user, "importance": importance} - return results diff --git a/docs_src/body_multiple_params/tutorial004_an_py39.py b/docs_src/body_multiple_params/tutorial004_an_py39.py deleted file mode 100644 index 567427c03..000000000 --- a/docs_src/body_multiple_params/tutorial004_an_py39.py +++ /dev/null @@ -1,33 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -class User(BaseModel): - username: str - full_name: Union[str, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int, - item: Item, - user: User, - importance: Annotated[int, Body(gt=0)], - q: Union[str, None] = None, -): - results = {"item_id": item_id, "item": item, "user": user, "importance": importance} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/body_multiple_params/tutorial004_py39.py b/docs_src/body_multiple_params/tutorial004_py39.py deleted file mode 100644 index 8ce4c7a97..000000000 --- a/docs_src/body_multiple_params/tutorial004_py39.py +++ /dev/null @@ -1,33 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -class User(BaseModel): - username: str - full_name: Union[str, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int, - item: Item, - user: User, - importance: int = Body(gt=0), - q: Union[str, None] = None, -): - results = {"item_id": item_id, "item": item, "user": user, "importance": importance} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/body_multiple_params/tutorial005_an_py39.py b/docs_src/body_multiple_params/tutorial005_an_py39.py deleted file mode 100644 index 9a52425c1..000000000 --- a/docs_src/body_multiple_params/tutorial005_an_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_multiple_params/tutorial005_py39.py b/docs_src/body_multiple_params/tutorial005_py39.py deleted file mode 100644 index 29e6e14b7..000000000 --- a/docs_src/body_multiple_params/tutorial005_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item = Body(embed=True)): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial001_py39.py b/docs_src/body_nested_models/tutorial001_py39.py deleted file mode 100644 index 37ef6dda5..000000000 --- a/docs_src/body_nested_models/tutorial001_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: list = [] - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial002_py39.py b/docs_src/body_nested_models/tutorial002_py39.py deleted file mode 100644 index 8a93a7233..000000000 --- a/docs_src/body_nested_models/tutorial002_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: list[str] = [] - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial003_py39.py b/docs_src/body_nested_models/tutorial003_py39.py deleted file mode 100644 index b590ece36..000000000 --- a/docs_src/body_nested_models/tutorial003_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial004_py39.py b/docs_src/body_nested_models/tutorial004_py39.py deleted file mode 100644 index dc2b175fb..000000000 --- a/docs_src/body_nested_models/tutorial004_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Image(BaseModel): - url: str - name: str - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - image: Union[Image, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial005_py39.py b/docs_src/body_nested_models/tutorial005_py39.py deleted file mode 100644 index 47db90008..000000000 --- a/docs_src/body_nested_models/tutorial005_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, HttpUrl - -app = FastAPI() - - -class Image(BaseModel): - url: HttpUrl - name: str - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - image: Union[Image, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial006_py39.py b/docs_src/body_nested_models/tutorial006_py39.py deleted file mode 100644 index b14409703..000000000 --- a/docs_src/body_nested_models/tutorial006_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, HttpUrl - -app = FastAPI() - - -class Image(BaseModel): - url: HttpUrl - name: str - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - images: Union[list[Image], None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial007_py39.py b/docs_src/body_nested_models/tutorial007_py39.py deleted file mode 100644 index 59cf01e23..000000000 --- a/docs_src/body_nested_models/tutorial007_py39.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, HttpUrl - -app = FastAPI() - - -class Image(BaseModel): - url: HttpUrl - name: str - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - images: Union[list[Image], None] = None - - -class Offer(BaseModel): - name: str - description: Union[str, None] = None - price: float - items: list[Item] - - -@app.post("/offers/") -async def create_offer(offer: Offer): - return offer diff --git a/docs_src/body_nested_models/tutorial008_py310.py b/docs_src/body_nested_models/tutorial008_py310.py new file mode 100644 index 000000000..854a7a5a4 --- /dev/null +++ b/docs_src/body_nested_models/tutorial008_py310.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI +from pydantic import BaseModel, HttpUrl + +app = FastAPI() + + +class Image(BaseModel): + url: HttpUrl + name: str + + +@app.post("/images/multiple/") +async def create_multiple_images(images: list[Image]): + return images diff --git a/docs_src/body_nested_models/tutorial009_py310.py b/docs_src/body_nested_models/tutorial009_py310.py new file mode 100644 index 000000000..59c1e5082 --- /dev/null +++ b/docs_src/body_nested_models/tutorial009_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.post("/index-weights/") +async def create_index_weights(weights: dict[int, float]): + return weights diff --git a/docs_src/body_updates/tutorial001_py39.py b/docs_src/body_updates/tutorial001_py39.py deleted file mode 100644 index 999bcdb82..000000000 --- a/docs_src/body_updates/tutorial001_py39.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from fastapi.encoders import jsonable_encoder -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: Union[str, None] = None - description: Union[str, None] = None - price: Union[float, None] = None - tax: float = 10.5 - tags: list[str] = [] - - -items = { - "foo": {"name": "Foo", "price": 50.2}, - "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2}, - "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []}, -} - - -@app.get("/items/{item_id}", response_model=Item) -async def read_item(item_id: str): - return items[item_id] - - -@app.put("/items/{item_id}", response_model=Item) -async def update_item(item_id: str, item: Item): - update_item_encoded = jsonable_encoder(item) - items[item_id] = update_item_encoded - return update_item_encoded diff --git a/docs_src/body_updates/tutorial002_py39.py b/docs_src/body_updates/tutorial002_py39.py deleted file mode 100644 index 3714b5a55..000000000 --- a/docs_src/body_updates/tutorial002_py39.py +++ /dev/null @@ -1,37 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from fastapi.encoders import jsonable_encoder -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: Union[str, None] = None - description: Union[str, None] = None - price: Union[float, None] = None - tax: float = 10.5 - tags: list[str] = [] - - -items = { - "foo": {"name": "Foo", "price": 50.2}, - "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2}, - "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []}, -} - - -@app.get("/items/{item_id}", response_model=Item) -async def read_item(item_id: str): - return items[item_id] - - -@app.patch("/items/{item_id}") -async def update_item(item_id: str, item: Item) -> Item: - stored_item_data = items[item_id] - stored_item_model = Item(**stored_item_data) - update_data = item.model_dump(exclude_unset=True) - updated_item = stored_item_model.model_copy(update=update_data) - items[item_id] = jsonable_encoder(updated_item) - return updated_item diff --git a/docs_src/conditional_openapi/tutorial001_py310.py b/docs_src/conditional_openapi/tutorial001_py310.py new file mode 100644 index 000000000..eedb0d274 --- /dev/null +++ b/docs_src/conditional_openapi/tutorial001_py310.py @@ -0,0 +1,16 @@ +from fastapi import FastAPI +from pydantic_settings import BaseSettings + + +class Settings(BaseSettings): + openapi_url: str = "/openapi.json" + + +settings = Settings() + +app = FastAPI(openapi_url=settings.openapi_url) + + +@app.get("/") +def root(): + return {"message": "Hello World"} diff --git a/docs_src/configure_swagger_ui/tutorial001_py310.py b/docs_src/configure_swagger_ui/tutorial001_py310.py new file mode 100644 index 000000000..6c24ce758 --- /dev/null +++ b/docs_src/configure_swagger_ui/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI(swagger_ui_parameters={"syntaxHighlight": False}) + + +@app.get("/users/{username}") +async def read_user(username: str): + return {"message": f"Hello {username}"} diff --git a/docs_src/configure_swagger_ui/tutorial002_py310.py b/docs_src/configure_swagger_ui/tutorial002_py310.py new file mode 100644 index 000000000..cc75c2196 --- /dev/null +++ b/docs_src/configure_swagger_ui/tutorial002_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI(swagger_ui_parameters={"syntaxHighlight": {"theme": "obsidian"}}) + + +@app.get("/users/{username}") +async def read_user(username: str): + return {"message": f"Hello {username}"} diff --git a/docs_src/configure_swagger_ui/tutorial003_py310.py b/docs_src/configure_swagger_ui/tutorial003_py310.py new file mode 100644 index 000000000..b4449f5c6 --- /dev/null +++ b/docs_src/configure_swagger_ui/tutorial003_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI(swagger_ui_parameters={"deepLinking": False}) + + +@app.get("/users/{username}") +async def read_user(username: str): + return {"message": f"Hello {username}"} diff --git a/docs_src/cookie_param_models/tutorial001_an_py39.py b/docs_src/cookie_param_models/tutorial001_an_py39.py deleted file mode 100644 index 3d90c2007..000000000 --- a/docs_src/cookie_param_models/tutorial001_an_py39.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Cookie, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Cookies(BaseModel): - session_id: str - fatebook_tracker: Union[str, None] = None - googall_tracker: Union[str, None] = None - - -@app.get("/items/") -async def read_items(cookies: Annotated[Cookies, Cookie()]): - return cookies diff --git a/docs_src/cookie_param_models/tutorial001_py39.py b/docs_src/cookie_param_models/tutorial001_py39.py deleted file mode 100644 index cc65c43e1..000000000 --- a/docs_src/cookie_param_models/tutorial001_py39.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Union - -from fastapi import Cookie, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Cookies(BaseModel): - session_id: str - fatebook_tracker: Union[str, None] = None - googall_tracker: Union[str, None] = None - - -@app.get("/items/") -async def read_items(cookies: Cookies = Cookie()): - return cookies diff --git a/docs_src/cookie_param_models/tutorial002_an_py39.py b/docs_src/cookie_param_models/tutorial002_an_py39.py deleted file mode 100644 index a906ce6a1..000000000 --- a/docs_src/cookie_param_models/tutorial002_an_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Cookie, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Cookies(BaseModel): - model_config = {"extra": "forbid"} - - session_id: str - fatebook_tracker: Union[str, None] = None - googall_tracker: Union[str, None] = None - - -@app.get("/items/") -async def read_items(cookies: Annotated[Cookies, Cookie()]): - return cookies diff --git a/docs_src/cookie_param_models/tutorial002_py39.py b/docs_src/cookie_param_models/tutorial002_py39.py deleted file mode 100644 index 9679e890f..000000000 --- a/docs_src/cookie_param_models/tutorial002_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import Cookie, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Cookies(BaseModel): - model_config = {"extra": "forbid"} - - session_id: str - fatebook_tracker: Union[str, None] = None - googall_tracker: Union[str, None] = None - - -@app.get("/items/") -async def read_items(cookies: Cookies = Cookie()): - return cookies diff --git a/docs_src/cookie_params/tutorial001_an_py39.py b/docs_src/cookie_params/tutorial001_an_py39.py deleted file mode 100644 index e18d0a332..000000000 --- a/docs_src/cookie_params/tutorial001_an_py39.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Cookie, FastAPI - -app = FastAPI() - - -@app.get("/items/") -async def read_items(ads_id: Annotated[Union[str, None], Cookie()] = None): - return {"ads_id": ads_id} diff --git a/docs_src/cookie_params/tutorial001_py39.py b/docs_src/cookie_params/tutorial001_py39.py deleted file mode 100644 index c4a497fda..000000000 --- a/docs_src/cookie_params/tutorial001_py39.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Union - -from fastapi import Cookie, FastAPI - -app = FastAPI() - - -@app.get("/items/") -async def read_items(ads_id: Union[str, None] = Cookie(default=None)): - return {"ads_id": ads_id} diff --git a/docs_src/cors/tutorial001_py310.py b/docs_src/cors/tutorial001_py310.py new file mode 100644 index 000000000..d59ab27ac --- /dev/null +++ b/docs_src/cors/tutorial001_py310.py @@ -0,0 +1,24 @@ +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware + +app = FastAPI() + +origins = [ + "http://localhost.tiangolo.com", + "https://localhost.tiangolo.com", + "http://localhost", + "http://localhost:8080", +] + +app.add_middleware( + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +@app.get("/") +async def main(): + return {"message": "Hello World"} diff --git a/docs_src/custom_docs_ui/tutorial001_py310.py b/docs_src/custom_docs_ui/tutorial001_py310.py new file mode 100644 index 000000000..1cfcce19a --- /dev/null +++ b/docs_src/custom_docs_ui/tutorial001_py310.py @@ -0,0 +1,38 @@ +from fastapi import FastAPI +from fastapi.openapi.docs import ( + get_redoc_html, + get_swagger_ui_html, + get_swagger_ui_oauth2_redirect_html, +) + +app = FastAPI(docs_url=None, redoc_url=None) + + +@app.get("/docs", include_in_schema=False) +async def custom_swagger_ui_html(): + return get_swagger_ui_html( + openapi_url=app.openapi_url, + title=app.title + " - Swagger UI", + oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, + swagger_js_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js", + swagger_css_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css", + ) + + +@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False) +async def swagger_ui_redirect(): + return get_swagger_ui_oauth2_redirect_html() + + +@app.get("/redoc", include_in_schema=False) +async def redoc_html(): + return get_redoc_html( + openapi_url=app.openapi_url, + title=app.title + " - ReDoc", + redoc_js_url="https://unpkg.com/redoc@2/bundles/redoc.standalone.js", + ) + + +@app.get("/users/{username}") +async def read_user(username: str): + return {"message": f"Hello {username}"} diff --git a/docs_src/custom_docs_ui/tutorial002_py310.py b/docs_src/custom_docs_ui/tutorial002_py310.py new file mode 100644 index 000000000..23ea368f8 --- /dev/null +++ b/docs_src/custom_docs_ui/tutorial002_py310.py @@ -0,0 +1,41 @@ +from fastapi import FastAPI +from fastapi.openapi.docs import ( + get_redoc_html, + get_swagger_ui_html, + get_swagger_ui_oauth2_redirect_html, +) +from fastapi.staticfiles import StaticFiles + +app = FastAPI(docs_url=None, redoc_url=None) + +app.mount("/static", StaticFiles(directory="static"), name="static") + + +@app.get("/docs", include_in_schema=False) +async def custom_swagger_ui_html(): + return get_swagger_ui_html( + openapi_url=app.openapi_url, + title=app.title + " - Swagger UI", + oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, + swagger_js_url="/static/swagger-ui-bundle.js", + swagger_css_url="/static/swagger-ui.css", + ) + + +@app.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False) +async def swagger_ui_redirect(): + return get_swagger_ui_oauth2_redirect_html() + + +@app.get("/redoc", include_in_schema=False) +async def redoc_html(): + return get_redoc_html( + openapi_url=app.openapi_url, + title=app.title + " - ReDoc", + redoc_js_url="/static/redoc.standalone.js", + ) + + +@app.get("/users/{username}") +async def read_user(username: str): + return {"message": f"Hello {username}"} diff --git a/docs_src/custom_request_and_route/tutorial001_an_py39.py b/docs_src/custom_request_and_route/tutorial001_an_py39.py deleted file mode 100644 index 076727e64..000000000 --- a/docs_src/custom_request_and_route/tutorial001_an_py39.py +++ /dev/null @@ -1,35 +0,0 @@ -import gzip -from typing import Annotated, Callable - -from fastapi import Body, FastAPI, Request, Response -from fastapi.routing import APIRoute - - -class GzipRequest(Request): - async def body(self) -> bytes: - if not hasattr(self, "_body"): - body = await super().body() - if "gzip" in self.headers.getlist("Content-Encoding"): - body = gzip.decompress(body) - self._body = body - return self._body - - -class GzipRoute(APIRoute): - def get_route_handler(self) -> Callable: - original_route_handler = super().get_route_handler() - - async def custom_route_handler(request: Request) -> Response: - request = GzipRequest(request.scope, request.receive) - return await original_route_handler(request) - - return custom_route_handler - - -app = FastAPI() -app.router.route_class = GzipRoute - - -@app.post("/sum") -async def sum_numbers(numbers: Annotated[list[int], Body()]): - return {"sum": sum(numbers)} diff --git a/docs_src/custom_request_and_route/tutorial001_py39.py b/docs_src/custom_request_and_route/tutorial001_py39.py deleted file mode 100644 index 54b20b942..000000000 --- a/docs_src/custom_request_and_route/tutorial001_py39.py +++ /dev/null @@ -1,35 +0,0 @@ -import gzip -from typing import Callable - -from fastapi import Body, FastAPI, Request, Response -from fastapi.routing import APIRoute - - -class GzipRequest(Request): - async def body(self) -> bytes: - if not hasattr(self, "_body"): - body = await super().body() - if "gzip" in self.headers.getlist("Content-Encoding"): - body = gzip.decompress(body) - self._body = body - return self._body - - -class GzipRoute(APIRoute): - def get_route_handler(self) -> Callable: - original_route_handler = super().get_route_handler() - - async def custom_route_handler(request: Request) -> Response: - request = GzipRequest(request.scope, request.receive) - return await original_route_handler(request) - - return custom_route_handler - - -app = FastAPI() -app.router.route_class = GzipRoute - - -@app.post("/sum") -async def sum_numbers(numbers: list[int] = Body()): - return {"sum": sum(numbers)} diff --git a/docs_src/custom_request_and_route/tutorial002_an_py39.py b/docs_src/custom_request_and_route/tutorial002_an_py39.py deleted file mode 100644 index e7de09de4..000000000 --- a/docs_src/custom_request_and_route/tutorial002_an_py39.py +++ /dev/null @@ -1,29 +0,0 @@ -from typing import Annotated, Callable - -from fastapi import Body, FastAPI, HTTPException, Request, Response -from fastapi.exceptions import RequestValidationError -from fastapi.routing import APIRoute - - -class ValidationErrorLoggingRoute(APIRoute): - def get_route_handler(self) -> Callable: - original_route_handler = super().get_route_handler() - - async def custom_route_handler(request: Request) -> Response: - try: - return await original_route_handler(request) - except RequestValidationError as exc: - body = await request.body() - detail = {"errors": exc.errors(), "body": body.decode()} - raise HTTPException(status_code=422, detail=detail) - - return custom_route_handler - - -app = FastAPI() -app.router.route_class = ValidationErrorLoggingRoute - - -@app.post("/") -async def sum_numbers(numbers: Annotated[list[int], Body()]): - return sum(numbers) diff --git a/docs_src/custom_request_and_route/tutorial002_py39.py b/docs_src/custom_request_and_route/tutorial002_py39.py deleted file mode 100644 index c4e474828..000000000 --- a/docs_src/custom_request_and_route/tutorial002_py39.py +++ /dev/null @@ -1,29 +0,0 @@ -from typing import Callable - -from fastapi import Body, FastAPI, HTTPException, Request, Response -from fastapi.exceptions import RequestValidationError -from fastapi.routing import APIRoute - - -class ValidationErrorLoggingRoute(APIRoute): - def get_route_handler(self) -> Callable: - original_route_handler = super().get_route_handler() - - async def custom_route_handler(request: Request) -> Response: - try: - return await original_route_handler(request) - except RequestValidationError as exc: - body = await request.body() - detail = {"errors": exc.errors(), "body": body.decode()} - raise HTTPException(status_code=422, detail=detail) - - return custom_route_handler - - -app = FastAPI() -app.router.route_class = ValidationErrorLoggingRoute - - -@app.post("/") -async def sum_numbers(numbers: list[int] = Body()): - return sum(numbers) diff --git a/docs_src/custom_request_and_route/tutorial003_py39.py b/docs_src/custom_request_and_route/tutorial003_py39.py deleted file mode 100644 index aabe76068..000000000 --- a/docs_src/custom_request_and_route/tutorial003_py39.py +++ /dev/null @@ -1,39 +0,0 @@ -import time -from typing import Callable - -from fastapi import APIRouter, FastAPI, Request, Response -from fastapi.routing import APIRoute - - -class TimedRoute(APIRoute): - def get_route_handler(self) -> Callable: - original_route_handler = super().get_route_handler() - - async def custom_route_handler(request: Request) -> Response: - before = time.time() - response: Response = await original_route_handler(request) - duration = time.time() - before - response.headers["X-Response-Time"] = str(duration) - print(f"route duration: {duration}") - print(f"route response: {response}") - print(f"route response headers: {response.headers}") - return response - - return custom_route_handler - - -app = FastAPI() -router = APIRouter(route_class=TimedRoute) - - -@app.get("/") -async def not_timed(): - return {"message": "Not timed"} - - -@router.get("/timed") -async def timed(): - return {"message": "It's the time of my life"} - - -app.include_router(router) diff --git a/docs_src/custom_response/tutorial001_py310.py b/docs_src/custom_response/tutorial001_py310.py new file mode 100644 index 000000000..0f09bdf77 --- /dev/null +++ b/docs_src/custom_response/tutorial001_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import UJSONResponse + +app = FastAPI() + + +@app.get("/items/", response_class=UJSONResponse) +async def read_items(): + return [{"item_id": "Foo"}] diff --git a/docs_src/custom_response/tutorial001b_py310.py b/docs_src/custom_response/tutorial001b_py310.py new file mode 100644 index 000000000..95e6ca763 --- /dev/null +++ b/docs_src/custom_response/tutorial001b_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import ORJSONResponse + +app = FastAPI() + + +@app.get("/items/", response_class=ORJSONResponse) +async def read_items(): + return ORJSONResponse([{"item_id": "Foo"}]) diff --git a/docs_src/custom_response/tutorial002_py310.py b/docs_src/custom_response/tutorial002_py310.py new file mode 100644 index 000000000..23c495867 --- /dev/null +++ b/docs_src/custom_response/tutorial002_py310.py @@ -0,0 +1,18 @@ +from fastapi import FastAPI +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +@app.get("/items/", response_class=HTMLResponse) +async def read_items(): + return """ + + + Some HTML in here + + +

Look ma! HTML!

+ + + """ diff --git a/docs_src/custom_response/tutorial003_py310.py b/docs_src/custom_response/tutorial003_py310.py new file mode 100644 index 000000000..51ad3c146 --- /dev/null +++ b/docs_src/custom_response/tutorial003_py310.py @@ -0,0 +1,19 @@ +from fastapi import FastAPI +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +@app.get("/items/") +async def read_items(): + html_content = """ + + + Some HTML in here + + +

Look ma! HTML!

+ + + """ + return HTMLResponse(content=html_content, status_code=200) diff --git a/docs_src/custom_response/tutorial004_py310.py b/docs_src/custom_response/tutorial004_py310.py new file mode 100644 index 000000000..0e90f2012 --- /dev/null +++ b/docs_src/custom_response/tutorial004_py310.py @@ -0,0 +1,23 @@ +from fastapi import FastAPI +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +def generate_html_response(): + html_content = """ + + + Some HTML in here + + +

Look ma! HTML!

+ + + """ + return HTMLResponse(content=html_content, status_code=200) + + +@app.get("/items/", response_class=HTMLResponse) +async def read_items(): + return generate_html_response() diff --git a/docs_src/custom_response/tutorial005_py310.py b/docs_src/custom_response/tutorial005_py310.py new file mode 100644 index 000000000..3d58f57fb --- /dev/null +++ b/docs_src/custom_response/tutorial005_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import PlainTextResponse + +app = FastAPI() + + +@app.get("/", response_class=PlainTextResponse) +async def main(): + return "Hello World" diff --git a/docs_src/custom_response/tutorial006_py310.py b/docs_src/custom_response/tutorial006_py310.py new file mode 100644 index 000000000..332f8f87f --- /dev/null +++ b/docs_src/custom_response/tutorial006_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import RedirectResponse + +app = FastAPI() + + +@app.get("/typer") +async def redirect_typer(): + return RedirectResponse("https://typer.tiangolo.com") diff --git a/docs_src/custom_response/tutorial006b_py310.py b/docs_src/custom_response/tutorial006b_py310.py new file mode 100644 index 000000000..03a7be399 --- /dev/null +++ b/docs_src/custom_response/tutorial006b_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import RedirectResponse + +app = FastAPI() + + +@app.get("/fastapi", response_class=RedirectResponse) +async def redirect_fastapi(): + return "https://fastapi.tiangolo.com" diff --git a/docs_src/custom_response/tutorial006c_py310.py b/docs_src/custom_response/tutorial006c_py310.py new file mode 100644 index 000000000..87c720364 --- /dev/null +++ b/docs_src/custom_response/tutorial006c_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import RedirectResponse + +app = FastAPI() + + +@app.get("/pydantic", response_class=RedirectResponse, status_code=302) +async def redirect_pydantic(): + return "https://docs.pydantic.dev/" diff --git a/docs_src/custom_response/tutorial007_py310.py b/docs_src/custom_response/tutorial007_py310.py new file mode 100644 index 000000000..e2a53a211 --- /dev/null +++ b/docs_src/custom_response/tutorial007_py310.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI +from fastapi.responses import StreamingResponse + +app = FastAPI() + + +async def fake_video_streamer(): + for i in range(10): + yield b"some fake video bytes" + + +@app.get("/") +async def main(): + return StreamingResponse(fake_video_streamer()) diff --git a/docs_src/custom_response/tutorial008_py310.py b/docs_src/custom_response/tutorial008_py310.py new file mode 100644 index 000000000..fc071cbee --- /dev/null +++ b/docs_src/custom_response/tutorial008_py310.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI +from fastapi.responses import StreamingResponse + +some_file_path = "large-video-file.mp4" +app = FastAPI() + + +@app.get("/") +def main(): + def iterfile(): # (1) + with open(some_file_path, mode="rb") as file_like: # (2) + yield from file_like # (3) + + return StreamingResponse(iterfile(), media_type="video/mp4") diff --git a/docs_src/custom_response/tutorial009_py310.py b/docs_src/custom_response/tutorial009_py310.py new file mode 100644 index 000000000..71cf50cc1 --- /dev/null +++ b/docs_src/custom_response/tutorial009_py310.py @@ -0,0 +1,10 @@ +from fastapi import FastAPI +from fastapi.responses import FileResponse + +some_file_path = "large-video-file.mp4" +app = FastAPI() + + +@app.get("/") +async def main(): + return FileResponse(some_file_path) diff --git a/docs_src/custom_response/tutorial009b_py310.py b/docs_src/custom_response/tutorial009b_py310.py new file mode 100644 index 000000000..27200ee4b --- /dev/null +++ b/docs_src/custom_response/tutorial009b_py310.py @@ -0,0 +1,10 @@ +from fastapi import FastAPI +from fastapi.responses import FileResponse + +some_file_path = "large-video-file.mp4" +app = FastAPI() + + +@app.get("/", response_class=FileResponse) +async def main(): + return some_file_path diff --git a/docs_src/custom_response/tutorial009c_py310.py b/docs_src/custom_response/tutorial009c_py310.py new file mode 100644 index 000000000..de6b6688e --- /dev/null +++ b/docs_src/custom_response/tutorial009c_py310.py @@ -0,0 +1,19 @@ +from typing import Any + +import orjson +from fastapi import FastAPI, Response + +app = FastAPI() + + +class CustomORJSONResponse(Response): + media_type = "application/json" + + def render(self, content: Any) -> bytes: + assert orjson is not None, "orjson must be installed" + return orjson.dumps(content, option=orjson.OPT_INDENT_2) + + +@app.get("/", response_class=CustomORJSONResponse) +async def main(): + return {"message": "Hello World"} diff --git a/docs_src/custom_response/tutorial010_py310.py b/docs_src/custom_response/tutorial010_py310.py new file mode 100644 index 000000000..57cb06260 --- /dev/null +++ b/docs_src/custom_response/tutorial010_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import ORJSONResponse + +app = FastAPI(default_response_class=ORJSONResponse) + + +@app.get("/items/") +async def read_items(): + return [{"item_id": "Foo"}] diff --git a/docs_src/dataclasses_/tutorial001_py39.py b/docs_src/dataclasses_/tutorial001_py39.py deleted file mode 100644 index 2954c391f..000000000 --- a/docs_src/dataclasses_/tutorial001_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from dataclasses import dataclass -from typing import Union - -from fastapi import FastAPI - - -@dataclass -class Item: - name: str - price: float - description: Union[str, None] = None - tax: Union[float, None] = None - - -app = FastAPI() - - -@app.post("/items/") -async def create_item(item: Item): - return item diff --git a/docs_src/dataclasses_/tutorial002_py39.py b/docs_src/dataclasses_/tutorial002_py39.py deleted file mode 100644 index 0c23765d8..000000000 --- a/docs_src/dataclasses_/tutorial002_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from dataclasses import dataclass, field -from typing import Union - -from fastapi import FastAPI - - -@dataclass -class Item: - name: str - price: float - tags: list[str] = field(default_factory=list) - description: Union[str, None] = None - tax: Union[float, None] = None - - -app = FastAPI() - - -@app.get("/items/next", response_model=Item) -async def read_next_item(): - return { - "name": "Island In The Moon", - "price": 12.99, - "description": "A place to be playin' and havin' fun", - "tags": ["breater"], - } diff --git a/docs_src/dataclasses_/tutorial003_py39.py b/docs_src/dataclasses_/tutorial003_py39.py deleted file mode 100644 index 991708c00..000000000 --- a/docs_src/dataclasses_/tutorial003_py39.py +++ /dev/null @@ -1,55 +0,0 @@ -from dataclasses import field # (1) -from typing import Union - -from fastapi import FastAPI -from pydantic.dataclasses import dataclass # (2) - - -@dataclass -class Item: - name: str - description: Union[str, None] = None - - -@dataclass -class Author: - name: str - items: list[Item] = field(default_factory=list) # (3) - - -app = FastAPI() - - -@app.post("/authors/{author_id}/items/", response_model=Author) # (4) -async def create_author_items(author_id: str, items: list[Item]): # (5) - return {"name": author_id, "items": items} # (6) - - -@app.get("/authors/", response_model=list[Author]) # (7) -def get_authors(): # (8) - return [ # (9) - { - "name": "Breaters", - "items": [ - { - "name": "Island In The Moon", - "description": "A place to be playin' and havin' fun", - }, - {"name": "Holy Buddies"}, - ], - }, - { - "name": "System of an Up", - "items": [ - { - "name": "Salt", - "description": "The kombucha mushroom people's favorite", - }, - {"name": "Pad Thai"}, - { - "name": "Lonely Night", - "description": "The mostests lonliest nightiest of allest", - }, - ], - }, - ] diff --git a/docs_src/debugging/tutorial001_py310.py b/docs_src/debugging/tutorial001_py310.py new file mode 100644 index 000000000..3de21d2a8 --- /dev/null +++ b/docs_src/debugging/tutorial001_py310.py @@ -0,0 +1,15 @@ +import uvicorn +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def root(): + a = "a" + b = "b" + a + return {"hello world": b} + + +if __name__ == "__main__": + uvicorn.run(app, host="0.0.0.0", port=8000) diff --git a/docs_src/dependencies/tutorial001_02_an_py39.py b/docs_src/dependencies/tutorial001_02_an_py39.py deleted file mode 100644 index df969ae9c..000000000 --- a/docs_src/dependencies/tutorial001_02_an_py39.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -async def common_parameters( - q: Union[str, None] = None, skip: int = 0, limit: int = 100 -): - return {"q": q, "skip": skip, "limit": limit} - - -CommonsDep = Annotated[dict, Depends(common_parameters)] - - -@app.get("/items/") -async def read_items(commons: CommonsDep): - return commons - - -@app.get("/users/") -async def read_users(commons: CommonsDep): - return commons diff --git a/docs_src/dependencies/tutorial001_an_py39.py b/docs_src/dependencies/tutorial001_an_py39.py deleted file mode 100644 index 5d9fe6ddf..000000000 --- a/docs_src/dependencies/tutorial001_an_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -async def common_parameters( - q: Union[str, None] = None, skip: int = 0, limit: int = 100 -): - return {"q": q, "skip": skip, "limit": limit} - - -@app.get("/items/") -async def read_items(commons: Annotated[dict, Depends(common_parameters)]): - return commons - - -@app.get("/users/") -async def read_users(commons: Annotated[dict, Depends(common_parameters)]): - return commons diff --git a/docs_src/dependencies/tutorial001_py39.py b/docs_src/dependencies/tutorial001_py39.py deleted file mode 100644 index b1275103a..000000000 --- a/docs_src/dependencies/tutorial001_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -async def common_parameters( - q: Union[str, None] = None, skip: int = 0, limit: int = 100 -): - return {"q": q, "skip": skip, "limit": limit} - - -@app.get("/items/") -async def read_items(commons: dict = Depends(common_parameters)): - return commons - - -@app.get("/users/") -async def read_users(commons: dict = Depends(common_parameters)): - return commons diff --git a/docs_src/dependencies/tutorial002_an_py39.py b/docs_src/dependencies/tutorial002_an_py39.py deleted file mode 100644 index 844a23c5a..000000000 --- a/docs_src/dependencies/tutorial002_an_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] - - -class CommonQueryParams: - def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): - self.q = q - self.skip = skip - self.limit = limit - - -@app.get("/items/") -async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]): - response = {} - if commons.q: - response.update({"q": commons.q}) - items = fake_items_db[commons.skip : commons.skip + commons.limit] - response.update({"items": items}) - return response diff --git a/docs_src/dependencies/tutorial002_py39.py b/docs_src/dependencies/tutorial002_py39.py deleted file mode 100644 index 8e863e4fa..000000000 --- a/docs_src/dependencies/tutorial002_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] - - -class CommonQueryParams: - def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): - self.q = q - self.skip = skip - self.limit = limit - - -@app.get("/items/") -async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)): - response = {} - if commons.q: - response.update({"q": commons.q}) - items = fake_items_db[commons.skip : commons.skip + commons.limit] - response.update({"items": items}) - return response diff --git a/docs_src/dependencies/tutorial003_an_py39.py b/docs_src/dependencies/tutorial003_an_py39.py deleted file mode 100644 index 9e9123ad2..000000000 --- a/docs_src/dependencies/tutorial003_an_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Annotated, Any, Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] - - -class CommonQueryParams: - def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): - self.q = q - self.skip = skip - self.limit = limit - - -@app.get("/items/") -async def read_items(commons: Annotated[Any, Depends(CommonQueryParams)]): - response = {} - if commons.q: - response.update({"q": commons.q}) - items = fake_items_db[commons.skip : commons.skip + commons.limit] - response.update({"items": items}) - return response diff --git a/docs_src/dependencies/tutorial003_py39.py b/docs_src/dependencies/tutorial003_py39.py deleted file mode 100644 index 34614e539..000000000 --- a/docs_src/dependencies/tutorial003_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] - - -class CommonQueryParams: - def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): - self.q = q - self.skip = skip - self.limit = limit - - -@app.get("/items/") -async def read_items(commons=Depends(CommonQueryParams)): - response = {} - if commons.q: - response.update({"q": commons.q}) - items = fake_items_db[commons.skip : commons.skip + commons.limit] - response.update({"items": items}) - return response diff --git a/docs_src/dependencies/tutorial004_an_py39.py b/docs_src/dependencies/tutorial004_an_py39.py deleted file mode 100644 index 74268626b..000000000 --- a/docs_src/dependencies/tutorial004_an_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] - - -class CommonQueryParams: - def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): - self.q = q - self.skip = skip - self.limit = limit - - -@app.get("/items/") -async def read_items(commons: Annotated[CommonQueryParams, Depends()]): - response = {} - if commons.q: - response.update({"q": commons.q}) - items = fake_items_db[commons.skip : commons.skip + commons.limit] - response.update({"items": items}) - return response diff --git a/docs_src/dependencies/tutorial004_py39.py b/docs_src/dependencies/tutorial004_py39.py deleted file mode 100644 index d9fe88148..000000000 --- a/docs_src/dependencies/tutorial004_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI - -app = FastAPI() - - -fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] - - -class CommonQueryParams: - def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): - self.q = q - self.skip = skip - self.limit = limit - - -@app.get("/items/") -async def read_items(commons: CommonQueryParams = Depends()): - response = {} - if commons.q: - response.update({"q": commons.q}) - items = fake_items_db[commons.skip : commons.skip + commons.limit] - response.update({"items": items}) - return response diff --git a/docs_src/dependencies/tutorial005_an_py39.py b/docs_src/dependencies/tutorial005_an_py39.py deleted file mode 100644 index d5dd8dca9..000000000 --- a/docs_src/dependencies/tutorial005_an_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Cookie, Depends, FastAPI - -app = FastAPI() - - -def query_extractor(q: Union[str, None] = None): - return q - - -def query_or_cookie_extractor( - q: Annotated[str, Depends(query_extractor)], - last_query: Annotated[Union[str, None], Cookie()] = None, -): - if not q: - return last_query - return q - - -@app.get("/items/") -async def read_query( - query_or_default: Annotated[str, Depends(query_or_cookie_extractor)], -): - return {"q_or_cookie": query_or_default} diff --git a/docs_src/dependencies/tutorial005_py39.py b/docs_src/dependencies/tutorial005_py39.py deleted file mode 100644 index 697332b5b..000000000 --- a/docs_src/dependencies/tutorial005_py39.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Union - -from fastapi import Cookie, Depends, FastAPI - -app = FastAPI() - - -def query_extractor(q: Union[str, None] = None): - return q - - -def query_or_cookie_extractor( - q: str = Depends(query_extractor), - last_query: Union[str, None] = Cookie(default=None), -): - if not q: - return last_query - return q - - -@app.get("/items/") -async def read_query(query_or_default: str = Depends(query_or_cookie_extractor)): - return {"q_or_cookie": query_or_default} diff --git a/docs_src/dependencies/tutorial006_an_py310.py b/docs_src/dependencies/tutorial006_an_py310.py new file mode 100644 index 000000000..11976ed6a --- /dev/null +++ b/docs_src/dependencies/tutorial006_an_py310.py @@ -0,0 +1,21 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI, Header, HTTPException + +app = FastAPI() + + +async def verify_token(x_token: Annotated[str, Header()]): + if x_token != "fake-super-secret-token": + raise HTTPException(status_code=400, detail="X-Token header invalid") + + +async def verify_key(x_key: Annotated[str, Header()]): + if x_key != "fake-super-secret-key": + raise HTTPException(status_code=400, detail="X-Key header invalid") + return x_key + + +@app.get("/items/", dependencies=[Depends(verify_token), Depends(verify_key)]) +async def read_items(): + return [{"item": "Foo"}, {"item": "Bar"}] diff --git a/docs_src/dependencies/tutorial006_py310.py b/docs_src/dependencies/tutorial006_py310.py new file mode 100644 index 000000000..9aff4154f --- /dev/null +++ b/docs_src/dependencies/tutorial006_py310.py @@ -0,0 +1,19 @@ +from fastapi import Depends, FastAPI, Header, HTTPException + +app = FastAPI() + + +async def verify_token(x_token: str = Header()): + if x_token != "fake-super-secret-token": + raise HTTPException(status_code=400, detail="X-Token header invalid") + + +async def verify_key(x_key: str = Header()): + if x_key != "fake-super-secret-key": + raise HTTPException(status_code=400, detail="X-Key header invalid") + return x_key + + +@app.get("/items/", dependencies=[Depends(verify_token), Depends(verify_key)]) +async def read_items(): + return [{"item": "Foo"}, {"item": "Bar"}] diff --git a/docs_src/dependencies/tutorial007_py310.py b/docs_src/dependencies/tutorial007_py310.py new file mode 100644 index 000000000..2e4ab4777 --- /dev/null +++ b/docs_src/dependencies/tutorial007_py310.py @@ -0,0 +1,6 @@ +async def get_db(): + db = DBSession() + try: + yield db + finally: + db.close() diff --git a/docs_src/dependencies/tutorial008_an_py310.py b/docs_src/dependencies/tutorial008_an_py310.py new file mode 100644 index 000000000..acc804c32 --- /dev/null +++ b/docs_src/dependencies/tutorial008_an_py310.py @@ -0,0 +1,27 @@ +from typing import Annotated + +from fastapi import Depends + + +async def dependency_a(): + dep_a = generate_dep_a() + try: + yield dep_a + finally: + dep_a.close() + + +async def dependency_b(dep_a: Annotated[DepA, Depends(dependency_a)]): + dep_b = generate_dep_b() + try: + yield dep_b + finally: + dep_b.close(dep_a) + + +async def dependency_c(dep_b: Annotated[DepB, Depends(dependency_b)]): + dep_c = generate_dep_c() + try: + yield dep_c + finally: + dep_c.close(dep_b) diff --git a/docs_src/dependencies/tutorial008_py310.py b/docs_src/dependencies/tutorial008_py310.py new file mode 100644 index 000000000..8472f642d --- /dev/null +++ b/docs_src/dependencies/tutorial008_py310.py @@ -0,0 +1,25 @@ +from fastapi import Depends + + +async def dependency_a(): + dep_a = generate_dep_a() + try: + yield dep_a + finally: + dep_a.close() + + +async def dependency_b(dep_a=Depends(dependency_a)): + dep_b = generate_dep_b() + try: + yield dep_b + finally: + dep_b.close(dep_a) + + +async def dependency_c(dep_b=Depends(dependency_b)): + dep_c = generate_dep_c() + try: + yield dep_c + finally: + dep_c.close(dep_b) diff --git a/docs_src/dependencies/tutorial008b_an_py310.py b/docs_src/dependencies/tutorial008b_an_py310.py new file mode 100644 index 000000000..3b8434c81 --- /dev/null +++ b/docs_src/dependencies/tutorial008b_an_py310.py @@ -0,0 +1,32 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI, HTTPException + +app = FastAPI() + + +data = { + "plumbus": {"description": "Freshly pickled plumbus", "owner": "Morty"}, + "portal-gun": {"description": "Gun to create portals", "owner": "Rick"}, +} + + +class OwnerError(Exception): + pass + + +def get_username(): + try: + yield "Rick" + except OwnerError as e: + raise HTTPException(status_code=400, detail=f"Owner error: {e}") + + +@app.get("/items/{item_id}") +def get_item(item_id: str, username: Annotated[str, Depends(get_username)]): + if item_id not in data: + raise HTTPException(status_code=404, detail="Item not found") + item = data[item_id] + if item["owner"] != username: + raise OwnerError(username) + return item diff --git a/docs_src/dependencies/tutorial008b_py310.py b/docs_src/dependencies/tutorial008b_py310.py new file mode 100644 index 000000000..163e96600 --- /dev/null +++ b/docs_src/dependencies/tutorial008b_py310.py @@ -0,0 +1,30 @@ +from fastapi import Depends, FastAPI, HTTPException + +app = FastAPI() + + +data = { + "plumbus": {"description": "Freshly pickled plumbus", "owner": "Morty"}, + "portal-gun": {"description": "Gun to create portals", "owner": "Rick"}, +} + + +class OwnerError(Exception): + pass + + +def get_username(): + try: + yield "Rick" + except OwnerError as e: + raise HTTPException(status_code=400, detail=f"Owner error: {e}") + + +@app.get("/items/{item_id}") +def get_item(item_id: str, username: str = Depends(get_username)): + if item_id not in data: + raise HTTPException(status_code=404, detail="Item not found") + item = data[item_id] + if item["owner"] != username: + raise OwnerError(username) + return item diff --git a/docs_src/dependencies/tutorial008c_an_py310.py b/docs_src/dependencies/tutorial008c_an_py310.py new file mode 100644 index 000000000..da92efa9c --- /dev/null +++ b/docs_src/dependencies/tutorial008c_an_py310.py @@ -0,0 +1,29 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI, HTTPException + +app = FastAPI() + + +class InternalError(Exception): + pass + + +def get_username(): + try: + yield "Rick" + except InternalError: + print("Oops, we didn't raise again, Britney 😱") + + +@app.get("/items/{item_id}") +def get_item(item_id: str, username: Annotated[str, Depends(get_username)]): + if item_id == "portal-gun": + raise InternalError( + f"The portal gun is too dangerous to be owned by {username}" + ) + if item_id != "plumbus": + raise HTTPException( + status_code=404, detail="Item not found, there's only a plumbus here" + ) + return item_id diff --git a/docs_src/dependencies/tutorial008c_py310.py b/docs_src/dependencies/tutorial008c_py310.py new file mode 100644 index 000000000..4b99a5a31 --- /dev/null +++ b/docs_src/dependencies/tutorial008c_py310.py @@ -0,0 +1,27 @@ +from fastapi import Depends, FastAPI, HTTPException + +app = FastAPI() + + +class InternalError(Exception): + pass + + +def get_username(): + try: + yield "Rick" + except InternalError: + print("Oops, we didn't raise again, Britney 😱") + + +@app.get("/items/{item_id}") +def get_item(item_id: str, username: str = Depends(get_username)): + if item_id == "portal-gun": + raise InternalError( + f"The portal gun is too dangerous to be owned by {username}" + ) + if item_id != "plumbus": + raise HTTPException( + status_code=404, detail="Item not found, there's only a plumbus here" + ) + return item_id diff --git a/docs_src/dependencies/tutorial008d_an_py310.py b/docs_src/dependencies/tutorial008d_an_py310.py new file mode 100644 index 000000000..99bd5cb91 --- /dev/null +++ b/docs_src/dependencies/tutorial008d_an_py310.py @@ -0,0 +1,30 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI, HTTPException + +app = FastAPI() + + +class InternalError(Exception): + pass + + +def get_username(): + try: + yield "Rick" + except InternalError: + print("We don't swallow the internal error here, we raise again 😎") + raise + + +@app.get("/items/{item_id}") +def get_item(item_id: str, username: Annotated[str, Depends(get_username)]): + if item_id == "portal-gun": + raise InternalError( + f"The portal gun is too dangerous to be owned by {username}" + ) + if item_id != "plumbus": + raise HTTPException( + status_code=404, detail="Item not found, there's only a plumbus here" + ) + return item_id diff --git a/docs_src/dependencies/tutorial008d_py310.py b/docs_src/dependencies/tutorial008d_py310.py new file mode 100644 index 000000000..93039343d --- /dev/null +++ b/docs_src/dependencies/tutorial008d_py310.py @@ -0,0 +1,28 @@ +from fastapi import Depends, FastAPI, HTTPException + +app = FastAPI() + + +class InternalError(Exception): + pass + + +def get_username(): + try: + yield "Rick" + except InternalError: + print("We don't swallow the internal error here, we raise again 😎") + raise + + +@app.get("/items/{item_id}") +def get_item(item_id: str, username: str = Depends(get_username)): + if item_id == "portal-gun": + raise InternalError( + f"The portal gun is too dangerous to be owned by {username}" + ) + if item_id != "plumbus": + raise HTTPException( + status_code=404, detail="Item not found, there's only a plumbus here" + ) + return item_id diff --git a/docs_src/dependencies/tutorial008e_an_py310.py b/docs_src/dependencies/tutorial008e_an_py310.py new file mode 100644 index 000000000..80a44c7e2 --- /dev/null +++ b/docs_src/dependencies/tutorial008e_an_py310.py @@ -0,0 +1,17 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI + +app = FastAPI() + + +def get_username(): + try: + yield "Rick" + finally: + print("Cleanup up before response is sent") + + +@app.get("/users/me") +def get_user_me(username: Annotated[str, Depends(get_username, scope="function")]): + return username diff --git a/docs_src/dependencies/tutorial008e_py310.py b/docs_src/dependencies/tutorial008e_py310.py new file mode 100644 index 000000000..1ed056e91 --- /dev/null +++ b/docs_src/dependencies/tutorial008e_py310.py @@ -0,0 +1,15 @@ +from fastapi import Depends, FastAPI + +app = FastAPI() + + +def get_username(): + try: + yield "Rick" + finally: + print("Cleanup up before response is sent") + + +@app.get("/users/me") +def get_user_me(username: str = Depends(get_username, scope="function")): + return username diff --git a/docs_src/dependencies/tutorial010_py310.py b/docs_src/dependencies/tutorial010_py310.py new file mode 100644 index 000000000..c27f1b170 --- /dev/null +++ b/docs_src/dependencies/tutorial010_py310.py @@ -0,0 +1,14 @@ +class MySuperContextManager: + def __init__(self): + self.db = DBSession() + + def __enter__(self): + return self.db + + def __exit__(self, exc_type, exc_value, traceback): + self.db.close() + + +async def get_db(): + with MySuperContextManager() as db: + yield db diff --git a/docs_src/dependencies/tutorial011_an_py310.py b/docs_src/dependencies/tutorial011_an_py310.py new file mode 100644 index 000000000..68b7434ec --- /dev/null +++ b/docs_src/dependencies/tutorial011_an_py310.py @@ -0,0 +1,23 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI + +app = FastAPI() + + +class FixedContentQueryChecker: + def __init__(self, fixed_content: str): + self.fixed_content = fixed_content + + def __call__(self, q: str = ""): + if q: + return self.fixed_content in q + return False + + +checker = FixedContentQueryChecker("bar") + + +@app.get("/query-checker/") +async def read_query_check(fixed_content_included: Annotated[bool, Depends(checker)]): + return {"fixed_content_in_query": fixed_content_included} diff --git a/docs_src/dependencies/tutorial011_py310.py b/docs_src/dependencies/tutorial011_py310.py new file mode 100644 index 000000000..5d22f6823 --- /dev/null +++ b/docs_src/dependencies/tutorial011_py310.py @@ -0,0 +1,21 @@ +from fastapi import Depends, FastAPI + +app = FastAPI() + + +class FixedContentQueryChecker: + def __init__(self, fixed_content: str): + self.fixed_content = fixed_content + + def __call__(self, q: str = ""): + if q: + return self.fixed_content in q + return False + + +checker = FixedContentQueryChecker("bar") + + +@app.get("/query-checker/") +async def read_query_check(fixed_content_included: bool = Depends(checker)): + return {"fixed_content_in_query": fixed_content_included} diff --git a/docs_src/dependencies/tutorial012_an_py310.py b/docs_src/dependencies/tutorial012_an_py310.py new file mode 100644 index 000000000..6503591fc --- /dev/null +++ b/docs_src/dependencies/tutorial012_an_py310.py @@ -0,0 +1,27 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI, Header, HTTPException + + +async def verify_token(x_token: Annotated[str, Header()]): + if x_token != "fake-super-secret-token": + raise HTTPException(status_code=400, detail="X-Token header invalid") + + +async def verify_key(x_key: Annotated[str, Header()]): + if x_key != "fake-super-secret-key": + raise HTTPException(status_code=400, detail="X-Key header invalid") + return x_key + + +app = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)]) + + +@app.get("/items/") +async def read_items(): + return [{"item": "Portal Gun"}, {"item": "Plumbus"}] + + +@app.get("/users/") +async def read_users(): + return [{"username": "Rick"}, {"username": "Morty"}] diff --git a/docs_src/dependencies/tutorial012_py310.py b/docs_src/dependencies/tutorial012_py310.py new file mode 100644 index 000000000..36ce6c711 --- /dev/null +++ b/docs_src/dependencies/tutorial012_py310.py @@ -0,0 +1,25 @@ +from fastapi import Depends, FastAPI, Header, HTTPException + + +async def verify_token(x_token: str = Header()): + if x_token != "fake-super-secret-token": + raise HTTPException(status_code=400, detail="X-Token header invalid") + + +async def verify_key(x_key: str = Header()): + if x_key != "fake-super-secret-key": + raise HTTPException(status_code=400, detail="X-Key header invalid") + return x_key + + +app = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)]) + + +@app.get("/items/") +async def read_items(): + return [{"item": "Portal Gun"}, {"item": "Plumbus"}] + + +@app.get("/users/") +async def read_users(): + return [{"username": "Rick"}, {"username": "Morty"}] diff --git a/docs_src/dependency_testing/tutorial001_an_py39.py b/docs_src/dependency_testing/tutorial001_an_py39.py deleted file mode 100644 index bccb0cdb1..000000000 --- a/docs_src/dependency_testing/tutorial001_an_py39.py +++ /dev/null @@ -1,59 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI -from fastapi.testclient import TestClient - -app = FastAPI() - - -async def common_parameters( - q: Union[str, None] = None, skip: int = 0, limit: int = 100 -): - return {"q": q, "skip": skip, "limit": limit} - - -@app.get("/items/") -async def read_items(commons: Annotated[dict, Depends(common_parameters)]): - return {"message": "Hello Items!", "params": commons} - - -@app.get("/users/") -async def read_users(commons: Annotated[dict, Depends(common_parameters)]): - return {"message": "Hello Users!", "params": commons} - - -client = TestClient(app) - - -async def override_dependency(q: Union[str, None] = None): - return {"q": q, "skip": 5, "limit": 10} - - -app.dependency_overrides[common_parameters] = override_dependency - - -def test_override_in_items(): - response = client.get("/items/") - assert response.status_code == 200 - assert response.json() == { - "message": "Hello Items!", - "params": {"q": None, "skip": 5, "limit": 10}, - } - - -def test_override_in_items_with_q(): - response = client.get("/items/?q=foo") - assert response.status_code == 200 - assert response.json() == { - "message": "Hello Items!", - "params": {"q": "foo", "skip": 5, "limit": 10}, - } - - -def test_override_in_items_with_params(): - response = client.get("/items/?q=foo&skip=100&limit=200") - assert response.status_code == 200 - assert response.json() == { - "message": "Hello Items!", - "params": {"q": "foo", "skip": 5, "limit": 10}, - } diff --git a/docs_src/dependency_testing/tutorial001_py39.py b/docs_src/dependency_testing/tutorial001_py39.py deleted file mode 100644 index a5fe1d9bf..000000000 --- a/docs_src/dependency_testing/tutorial001_py39.py +++ /dev/null @@ -1,59 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI -from fastapi.testclient import TestClient - -app = FastAPI() - - -async def common_parameters( - q: Union[str, None] = None, skip: int = 0, limit: int = 100 -): - return {"q": q, "skip": skip, "limit": limit} - - -@app.get("/items/") -async def read_items(commons: dict = Depends(common_parameters)): - return {"message": "Hello Items!", "params": commons} - - -@app.get("/users/") -async def read_users(commons: dict = Depends(common_parameters)): - return {"message": "Hello Users!", "params": commons} - - -client = TestClient(app) - - -async def override_dependency(q: Union[str, None] = None): - return {"q": q, "skip": 5, "limit": 10} - - -app.dependency_overrides[common_parameters] = override_dependency - - -def test_override_in_items(): - response = client.get("/items/") - assert response.status_code == 200 - assert response.json() == { - "message": "Hello Items!", - "params": {"q": None, "skip": 5, "limit": 10}, - } - - -def test_override_in_items_with_q(): - response = client.get("/items/?q=foo") - assert response.status_code == 200 - assert response.json() == { - "message": "Hello Items!", - "params": {"q": "foo", "skip": 5, "limit": 10}, - } - - -def test_override_in_items_with_params(): - response = client.get("/items/?q=foo&skip=100&limit=200") - assert response.status_code == 200 - assert response.json() == { - "message": "Hello Items!", - "params": {"q": "foo", "skip": 5, "limit": 10}, - } diff --git a/docs_src/encoder/tutorial001_py39.py b/docs_src/encoder/tutorial001_py39.py deleted file mode 100644 index 5f7e7061e..000000000 --- a/docs_src/encoder/tutorial001_py39.py +++ /dev/null @@ -1,23 +0,0 @@ -from datetime import datetime -from typing import Union - -from fastapi import FastAPI -from fastapi.encoders import jsonable_encoder -from pydantic import BaseModel - -fake_db = {} - - -class Item(BaseModel): - title: str - timestamp: datetime - description: Union[str, None] = None - - -app = FastAPI() - - -@app.put("/items/{id}") -def update_item(id: str, item: Item): - json_compatible_item_data = jsonable_encoder(item) - fake_db[id] = json_compatible_item_data diff --git a/docs_src/events/tutorial001_py310.py b/docs_src/events/tutorial001_py310.py new file mode 100644 index 000000000..128004c9f --- /dev/null +++ b/docs_src/events/tutorial001_py310.py @@ -0,0 +1,16 @@ +from fastapi import FastAPI + +app = FastAPI() + +items = {} + + +@app.on_event("startup") +async def startup_event(): + items["foo"] = {"name": "Fighters"} + items["bar"] = {"name": "Tenders"} + + +@app.get("/items/{item_id}") +async def read_items(item_id: str): + return items[item_id] diff --git a/docs_src/events/tutorial002_py310.py b/docs_src/events/tutorial002_py310.py new file mode 100644 index 000000000..a71fea802 --- /dev/null +++ b/docs_src/events/tutorial002_py310.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.on_event("shutdown") +def shutdown_event(): + with open("log.txt", mode="a") as log: + log.write("Application shutdown") + + +@app.get("/items/") +async def read_items(): + return [{"name": "Foo"}] diff --git a/docs_src/events/tutorial003_py310.py b/docs_src/events/tutorial003_py310.py new file mode 100644 index 000000000..2b650590b --- /dev/null +++ b/docs_src/events/tutorial003_py310.py @@ -0,0 +1,28 @@ +from contextlib import asynccontextmanager + +from fastapi import FastAPI + + +def fake_answer_to_everything_ml_model(x: float): + return x * 42 + + +ml_models = {} + + +@asynccontextmanager +async def lifespan(app: FastAPI): + # Load the ML model + ml_models["answer_to_everything"] = fake_answer_to_everything_ml_model + yield + # Clean up the ML models and release the resources + ml_models.clear() + + +app = FastAPI(lifespan=lifespan) + + +@app.get("/predict") +async def predict(x: float): + result = ml_models["answer_to_everything"](x) + return {"result": result} diff --git a/docs_src/extending_openapi/tutorial001_py310.py b/docs_src/extending_openapi/tutorial001_py310.py new file mode 100644 index 000000000..35e31c0e0 --- /dev/null +++ b/docs_src/extending_openapi/tutorial001_py310.py @@ -0,0 +1,29 @@ +from fastapi import FastAPI +from fastapi.openapi.utils import get_openapi + +app = FastAPI() + + +@app.get("/items/") +async def read_items(): + return [{"name": "Foo"}] + + +def custom_openapi(): + if app.openapi_schema: + return app.openapi_schema + openapi_schema = get_openapi( + title="Custom title", + version="2.5.0", + summary="This is a very custom OpenAPI schema", + description="Here's a longer description of the custom **OpenAPI** schema", + routes=app.routes, + ) + openapi_schema["info"]["x-logo"] = { + "url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" + } + app.openapi_schema = openapi_schema + return app.openapi_schema + + +app.openapi = custom_openapi diff --git a/docs_src/extra_data_types/tutorial001_an_py39.py b/docs_src/extra_data_types/tutorial001_an_py39.py deleted file mode 100644 index fa3551d66..000000000 --- a/docs_src/extra_data_types/tutorial001_an_py39.py +++ /dev/null @@ -1,28 +0,0 @@ -from datetime import datetime, time, timedelta -from typing import Annotated, Union -from uuid import UUID - -from fastapi import Body, FastAPI - -app = FastAPI() - - -@app.put("/items/{item_id}") -async def read_items( - item_id: UUID, - start_datetime: Annotated[datetime, Body()], - end_datetime: Annotated[datetime, Body()], - process_after: Annotated[timedelta, Body()], - repeat_at: Annotated[Union[time, None], Body()] = None, -): - start_process = start_datetime + process_after - duration = end_datetime - start_process - return { - "item_id": item_id, - "start_datetime": start_datetime, - "end_datetime": end_datetime, - "process_after": process_after, - "repeat_at": repeat_at, - "start_process": start_process, - "duration": duration, - } diff --git a/docs_src/extra_data_types/tutorial001_py39.py b/docs_src/extra_data_types/tutorial001_py39.py deleted file mode 100644 index 71de958ff..000000000 --- a/docs_src/extra_data_types/tutorial001_py39.py +++ /dev/null @@ -1,28 +0,0 @@ -from datetime import datetime, time, timedelta -from typing import Union -from uuid import UUID - -from fastapi import Body, FastAPI - -app = FastAPI() - - -@app.put("/items/{item_id}") -async def read_items( - item_id: UUID, - start_datetime: datetime = Body(), - end_datetime: datetime = Body(), - process_after: timedelta = Body(), - repeat_at: Union[time, None] = Body(default=None), -): - start_process = start_datetime + process_after - duration = end_datetime - start_process - return { - "item_id": item_id, - "start_datetime": start_datetime, - "end_datetime": end_datetime, - "process_after": process_after, - "repeat_at": repeat_at, - "start_process": start_process, - "duration": duration, - } diff --git a/docs_src/extra_models/tutorial001_py39.py b/docs_src/extra_models/tutorial001_py39.py deleted file mode 100644 index 327ffcdf0..000000000 --- a/docs_src/extra_models/tutorial001_py39.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, EmailStr - -app = FastAPI() - - -class UserIn(BaseModel): - username: str - password: str - email: EmailStr - full_name: Union[str, None] = None - - -class UserOut(BaseModel): - username: str - email: EmailStr - full_name: Union[str, None] = None - - -class UserInDB(BaseModel): - username: str - hashed_password: str - email: EmailStr - full_name: Union[str, None] = None - - -def fake_password_hasher(raw_password: str): - return "supersecret" + raw_password - - -def fake_save_user(user_in: UserIn): - hashed_password = fake_password_hasher(user_in.password) - user_in_db = UserInDB(**user_in.model_dump(), hashed_password=hashed_password) - print("User saved! ..not really") - return user_in_db - - -@app.post("/user/", response_model=UserOut) -async def create_user(user_in: UserIn): - user_saved = fake_save_user(user_in) - return user_saved diff --git a/docs_src/extra_models/tutorial002_py39.py b/docs_src/extra_models/tutorial002_py39.py deleted file mode 100644 index 654379601..000000000 --- a/docs_src/extra_models/tutorial002_py39.py +++ /dev/null @@ -1,41 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, EmailStr - -app = FastAPI() - - -class UserBase(BaseModel): - username: str - email: EmailStr - full_name: Union[str, None] = None - - -class UserIn(UserBase): - password: str - - -class UserOut(UserBase): - pass - - -class UserInDB(UserBase): - hashed_password: str - - -def fake_password_hasher(raw_password: str): - return "supersecret" + raw_password - - -def fake_save_user(user_in: UserIn): - hashed_password = fake_password_hasher(user_in.password) - user_in_db = UserInDB(**user_in.model_dump(), hashed_password=hashed_password) - print("User saved! ..not really") - return user_in_db - - -@app.post("/user/", response_model=UserOut) -async def create_user(user_in: UserIn): - user_saved = fake_save_user(user_in) - return user_saved diff --git a/docs_src/extra_models/tutorial003_py39.py b/docs_src/extra_models/tutorial003_py39.py deleted file mode 100644 index 06675cbc0..000000000 --- a/docs_src/extra_models/tutorial003_py39.py +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class BaseItem(BaseModel): - description: str - type: str - - -class CarItem(BaseItem): - type: str = "car" - - -class PlaneItem(BaseItem): - type: str = "plane" - size: int - - -items = { - "item1": {"description": "All my friends drive a low rider", "type": "car"}, - "item2": { - "description": "Music is my aeroplane, it's my aeroplane", - "type": "plane", - "size": 5, - }, -} - - -@app.get("/items/{item_id}", response_model=Union[PlaneItem, CarItem]) -async def read_item(item_id: str): - return items[item_id] diff --git a/docs_src/extra_models/tutorial004_py310.py b/docs_src/extra_models/tutorial004_py310.py new file mode 100644 index 000000000..28cacde4d --- /dev/null +++ b/docs_src/extra_models/tutorial004_py310.py @@ -0,0 +1,20 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + description: str + + +items = [ + {"name": "Foo", "description": "There comes my hero"}, + {"name": "Red", "description": "It's my aeroplane"}, +] + + +@app.get("/items/", response_model=list[Item]) +async def read_items(): + return items diff --git a/docs_src/extra_models/tutorial005_py310.py b/docs_src/extra_models/tutorial005_py310.py new file mode 100644 index 000000000..9da2a0a0f --- /dev/null +++ b/docs_src/extra_models/tutorial005_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/keyword-weights/", response_model=dict[str, float]) +async def read_keyword_weights(): + return {"foo": 2.3, "bar": 3.4} diff --git a/docs_src/first_steps/tutorial001_py310.py b/docs_src/first_steps/tutorial001_py310.py new file mode 100644 index 000000000..ee60be1f9 --- /dev/null +++ b/docs_src/first_steps/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +async def root(): + return {"message": "Hello World"} diff --git a/docs_src/first_steps/tutorial003_py310.py b/docs_src/first_steps/tutorial003_py310.py new file mode 100644 index 000000000..e30b827ea --- /dev/null +++ b/docs_src/first_steps/tutorial003_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/") +def root(): + return {"message": "Hello World"} diff --git a/docs_src/generate_clients/tutorial001_py310.py b/docs_src/generate_clients/tutorial001_py310.py new file mode 100644 index 000000000..6a5ae2320 --- /dev/null +++ b/docs_src/generate_clients/tutorial001_py310.py @@ -0,0 +1,26 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + price: float + + +class ResponseMessage(BaseModel): + message: str + + +@app.post("/items/", response_model=ResponseMessage) +async def create_item(item: Item): + return {"message": "item received"} + + +@app.get("/items/", response_model=list[Item]) +async def get_items(): + return [ + {"name": "Plumbus", "price": 3}, + {"name": "Portal Gun", "price": 9001}, + ] diff --git a/docs_src/generate_clients/tutorial002_py310.py b/docs_src/generate_clients/tutorial002_py310.py new file mode 100644 index 000000000..83309760b --- /dev/null +++ b/docs_src/generate_clients/tutorial002_py310.py @@ -0,0 +1,36 @@ +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Item(BaseModel): + name: str + price: float + + +class ResponseMessage(BaseModel): + message: str + + +class User(BaseModel): + username: str + email: str + + +@app.post("/items/", response_model=ResponseMessage, tags=["items"]) +async def create_item(item: Item): + return {"message": "Item received"} + + +@app.get("/items/", response_model=list[Item], tags=["items"]) +async def get_items(): + return [ + {"name": "Plumbus", "price": 3}, + {"name": "Portal Gun", "price": 9001}, + ] + + +@app.post("/users/", response_model=ResponseMessage, tags=["users"]) +async def create_user(user: User): + return {"message": "User received"} diff --git a/docs_src/generate_clients/tutorial003_py310.py b/docs_src/generate_clients/tutorial003_py310.py new file mode 100644 index 000000000..40722cf10 --- /dev/null +++ b/docs_src/generate_clients/tutorial003_py310.py @@ -0,0 +1,42 @@ +from fastapi import FastAPI +from fastapi.routing import APIRoute +from pydantic import BaseModel + + +def custom_generate_unique_id(route: APIRoute): + return f"{route.tags[0]}-{route.name}" + + +app = FastAPI(generate_unique_id_function=custom_generate_unique_id) + + +class Item(BaseModel): + name: str + price: float + + +class ResponseMessage(BaseModel): + message: str + + +class User(BaseModel): + username: str + email: str + + +@app.post("/items/", response_model=ResponseMessage, tags=["items"]) +async def create_item(item: Item): + return {"message": "Item received"} + + +@app.get("/items/", response_model=list[Item], tags=["items"]) +async def get_items(): + return [ + {"name": "Plumbus", "price": 3}, + {"name": "Portal Gun", "price": 9001}, + ] + + +@app.post("/users/", response_model=ResponseMessage, tags=["users"]) +async def create_user(user: User): + return {"message": "User received"} diff --git a/docs_src/generate_clients/tutorial004_py310.py b/docs_src/generate_clients/tutorial004_py310.py new file mode 100644 index 000000000..894dc7f8d --- /dev/null +++ b/docs_src/generate_clients/tutorial004_py310.py @@ -0,0 +1,15 @@ +import json +from pathlib import Path + +file_path = Path("./openapi.json") +openapi_content = json.loads(file_path.read_text()) + +for path_data in openapi_content["paths"].values(): + for operation in path_data.values(): + tag = operation["tags"][0] + operation_id = operation["operationId"] + to_remove = f"{tag}-" + new_operation_id = operation_id[len(to_remove) :] + operation["operationId"] = new_operation_id + +file_path.write_text(json.dumps(openapi_content)) diff --git a/docs_src/graphql_/tutorial001_py310.py b/docs_src/graphql_/tutorial001_py310.py new file mode 100644 index 000000000..e92b2d71c --- /dev/null +++ b/docs_src/graphql_/tutorial001_py310.py @@ -0,0 +1,25 @@ +import strawberry +from fastapi import FastAPI +from strawberry.fastapi import GraphQLRouter + + +@strawberry.type +class User: + name: str + age: int + + +@strawberry.type +class Query: + @strawberry.field + def user(self) -> User: + return User(name="Patrick", age=100) + + +schema = strawberry.Schema(query=Query) + + +graphql_app = GraphQLRouter(schema) + +app = FastAPI() +app.include_router(graphql_app, prefix="/graphql") diff --git a/docs_src/handling_errors/tutorial001_py310.py b/docs_src/handling_errors/tutorial001_py310.py new file mode 100644 index 000000000..e5f32aac2 --- /dev/null +++ b/docs_src/handling_errors/tutorial001_py310.py @@ -0,0 +1,12 @@ +from fastapi import FastAPI, HTTPException + +app = FastAPI() + +items = {"foo": "The Foo Wrestlers"} + + +@app.get("/items/{item_id}") +async def read_item(item_id: str): + if item_id not in items: + raise HTTPException(status_code=404, detail="Item not found") + return {"item": items[item_id]} diff --git a/docs_src/handling_errors/tutorial002_py310.py b/docs_src/handling_errors/tutorial002_py310.py new file mode 100644 index 000000000..e48c295c9 --- /dev/null +++ b/docs_src/handling_errors/tutorial002_py310.py @@ -0,0 +1,16 @@ +from fastapi import FastAPI, HTTPException + +app = FastAPI() + +items = {"foo": "The Foo Wrestlers"} + + +@app.get("/items-header/{item_id}") +async def read_item_header(item_id: str): + if item_id not in items: + raise HTTPException( + status_code=404, + detail="Item not found", + headers={"X-Error": "There goes my error"}, + ) + return {"item": items[item_id]} diff --git a/docs_src/handling_errors/tutorial003_py310.py b/docs_src/handling_errors/tutorial003_py310.py new file mode 100644 index 000000000..791cd6838 --- /dev/null +++ b/docs_src/handling_errors/tutorial003_py310.py @@ -0,0 +1,25 @@ +from fastapi import FastAPI, Request +from fastapi.responses import JSONResponse + + +class UnicornException(Exception): + def __init__(self, name: str): + self.name = name + + +app = FastAPI() + + +@app.exception_handler(UnicornException) +async def unicorn_exception_handler(request: Request, exc: UnicornException): + return JSONResponse( + status_code=418, + content={"message": f"Oops! {exc.name} did something. There goes a rainbow..."}, + ) + + +@app.get("/unicorns/{name}") +async def read_unicorn(name: str): + if name == "yolo": + raise UnicornException(name=name) + return {"unicorn_name": name} diff --git a/docs_src/handling_errors/tutorial004_py310.py b/docs_src/handling_errors/tutorial004_py310.py new file mode 100644 index 000000000..ae50807e9 --- /dev/null +++ b/docs_src/handling_errors/tutorial004_py310.py @@ -0,0 +1,26 @@ +from fastapi import FastAPI, HTTPException +from fastapi.exceptions import RequestValidationError +from fastapi.responses import PlainTextResponse +from starlette.exceptions import HTTPException as StarletteHTTPException + +app = FastAPI() + + +@app.exception_handler(StarletteHTTPException) +async def http_exception_handler(request, exc): + return PlainTextResponse(str(exc.detail), status_code=exc.status_code) + + +@app.exception_handler(RequestValidationError) +async def validation_exception_handler(request, exc: RequestValidationError): + message = "Validation errors:" + for error in exc.errors(): + message += f"\nField: {error['loc']}, Error: {error['msg']}" + return PlainTextResponse(message, status_code=400) + + +@app.get("/items/{item_id}") +async def read_item(item_id: int): + if item_id == 3: + raise HTTPException(status_code=418, detail="Nope! I don't like 3.") + return {"item_id": item_id} diff --git a/docs_src/handling_errors/tutorial005_py310.py b/docs_src/handling_errors/tutorial005_py310.py new file mode 100644 index 000000000..0e04fa086 --- /dev/null +++ b/docs_src/handling_errors/tutorial005_py310.py @@ -0,0 +1,25 @@ +from fastapi import FastAPI, Request +from fastapi.encoders import jsonable_encoder +from fastapi.exceptions import RequestValidationError +from fastapi.responses import JSONResponse +from pydantic import BaseModel + +app = FastAPI() + + +@app.exception_handler(RequestValidationError) +async def validation_exception_handler(request: Request, exc: RequestValidationError): + return JSONResponse( + status_code=422, + content=jsonable_encoder({"detail": exc.errors(), "body": exc.body}), + ) + + +class Item(BaseModel): + title: str + size: int + + +@app.post("/items/") +async def create_item(item: Item): + return item diff --git a/docs_src/handling_errors/tutorial006_py310.py b/docs_src/handling_errors/tutorial006_py310.py new file mode 100644 index 000000000..e05160d7e --- /dev/null +++ b/docs_src/handling_errors/tutorial006_py310.py @@ -0,0 +1,28 @@ +from fastapi import FastAPI, HTTPException +from fastapi.exception_handlers import ( + http_exception_handler, + request_validation_exception_handler, +) +from fastapi.exceptions import RequestValidationError +from starlette.exceptions import HTTPException as StarletteHTTPException + +app = FastAPI() + + +@app.exception_handler(StarletteHTTPException) +async def custom_http_exception_handler(request, exc): + print(f"OMG! An HTTP error!: {repr(exc)}") + return await http_exception_handler(request, exc) + + +@app.exception_handler(RequestValidationError) +async def validation_exception_handler(request, exc): + print(f"OMG! The client sent invalid data!: {exc}") + return await request_validation_exception_handler(request, exc) + + +@app.get("/items/{item_id}") +async def read_item(item_id: int): + if item_id == 3: + raise HTTPException(status_code=418, detail="Nope! I don't like 3.") + return {"item_id": item_id} diff --git a/docs_src/header_param_models/tutorial001_an_py39.py b/docs_src/header_param_models/tutorial001_an_py39.py deleted file mode 100644 index 51a5f94fc..000000000 --- a/docs_src/header_param_models/tutorial001_an_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items(headers: Annotated[CommonHeaders, Header()]): - return headers diff --git a/docs_src/header_param_models/tutorial001_py39.py b/docs_src/header_param_models/tutorial001_py39.py deleted file mode 100644 index 4c1137813..000000000 --- a/docs_src/header_param_models/tutorial001_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items(headers: CommonHeaders = Header()): - return headers diff --git a/docs_src/header_param_models/tutorial002_an_py39.py b/docs_src/header_param_models/tutorial002_an_py39.py deleted file mode 100644 index ca5208c9d..000000000 --- a/docs_src/header_param_models/tutorial002_an_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - model_config = {"extra": "forbid"} - - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items(headers: Annotated[CommonHeaders, Header()]): - return headers diff --git a/docs_src/header_param_models/tutorial002_py39.py b/docs_src/header_param_models/tutorial002_py39.py deleted file mode 100644 index f8ce559a7..000000000 --- a/docs_src/header_param_models/tutorial002_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - model_config = {"extra": "forbid"} - - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items(headers: CommonHeaders = Header()): - return headers diff --git a/docs_src/header_param_models/tutorial003_an_py39.py b/docs_src/header_param_models/tutorial003_an_py39.py deleted file mode 100644 index 8be6b01d0..000000000 --- a/docs_src/header_param_models/tutorial003_an_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items( - headers: Annotated[CommonHeaders, Header(convert_underscores=False)], -): - return headers diff --git a/docs_src/header_param_models/tutorial003_py39.py b/docs_src/header_param_models/tutorial003_py39.py deleted file mode 100644 index 848c34111..000000000 --- a/docs_src/header_param_models/tutorial003_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: list[str] = [] - - -@app.get("/items/") -async def read_items(headers: CommonHeaders = Header(convert_underscores=False)): - return headers diff --git a/docs_src/header_params/tutorial001_an_py39.py b/docs_src/header_params/tutorial001_an_py39.py deleted file mode 100644 index 1fbe3bb99..000000000 --- a/docs_src/header_params/tutorial001_an_py39.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Header - -app = FastAPI() - - -@app.get("/items/") -async def read_items(user_agent: Annotated[Union[str, None], Header()] = None): - return {"User-Agent": user_agent} diff --git a/docs_src/header_params/tutorial001_py39.py b/docs_src/header_params/tutorial001_py39.py deleted file mode 100644 index 74429c8e2..000000000 --- a/docs_src/header_params/tutorial001_py39.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header - -app = FastAPI() - - -@app.get("/items/") -async def read_items(user_agent: Union[str, None] = Header(default=None)): - return {"User-Agent": user_agent} diff --git a/docs_src/header_params/tutorial002_an_py39.py b/docs_src/header_params/tutorial002_an_py39.py deleted file mode 100644 index 008e4b6e1..000000000 --- a/docs_src/header_params/tutorial002_an_py39.py +++ /dev/null @@ -1,14 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Header - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - strange_header: Annotated[ - Union[str, None], Header(convert_underscores=False) - ] = None, -): - return {"strange_header": strange_header} diff --git a/docs_src/header_params/tutorial002_py39.py b/docs_src/header_params/tutorial002_py39.py deleted file mode 100644 index 0a34f17cc..000000000 --- a/docs_src/header_params/tutorial002_py39.py +++ /dev/null @@ -1,12 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - strange_header: Union[str, None] = Header(default=None, convert_underscores=False), -): - return {"strange_header": strange_header} diff --git a/docs_src/header_params/tutorial003_an_py39.py b/docs_src/header_params/tutorial003_an_py39.py deleted file mode 100644 index 5aad89407..000000000 --- a/docs_src/header_params/tutorial003_an_py39.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Header - -app = FastAPI() - - -@app.get("/items/") -async def read_items(x_token: Annotated[Union[list[str], None], Header()] = None): - return {"X-Token values": x_token} diff --git a/docs_src/header_params/tutorial003_py39.py b/docs_src/header_params/tutorial003_py39.py deleted file mode 100644 index 34437db16..000000000 --- a/docs_src/header_params/tutorial003_py39.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header - -app = FastAPI() - - -@app.get("/items/") -async def read_items(x_token: Union[list[str], None] = Header(default=None)): - return {"X-Token values": x_token} diff --git a/docs_src/metadata/tutorial001_1_py310.py b/docs_src/metadata/tutorial001_1_py310.py new file mode 100644 index 000000000..419232d86 --- /dev/null +++ b/docs_src/metadata/tutorial001_1_py310.py @@ -0,0 +1,38 @@ +from fastapi import FastAPI + +description = """ +ChimichangApp API helps you do awesome stuff. 🚀 + +## Items + +You can **read items**. + +## Users + +You will be able to: + +* **Create users** (_not implemented_). +* **Read users** (_not implemented_). +""" + +app = FastAPI( + title="ChimichangApp", + description=description, + summary="Deadpool's favorite app. Nuff said.", + version="0.0.1", + terms_of_service="http://example.com/terms/", + contact={ + "name": "Deadpoolio the Amazing", + "url": "http://x-force.example.com/contact/", + "email": "dp@x-force.example.com", + }, + license_info={ + "name": "Apache 2.0", + "identifier": "Apache-2.0", + }, +) + + +@app.get("/items/") +async def read_items(): + return [{"name": "Katana"}] diff --git a/docs_src/metadata/tutorial001_py310.py b/docs_src/metadata/tutorial001_py310.py new file mode 100644 index 000000000..76656e81b --- /dev/null +++ b/docs_src/metadata/tutorial001_py310.py @@ -0,0 +1,38 @@ +from fastapi import FastAPI + +description = """ +ChimichangApp API helps you do awesome stuff. 🚀 + +## Items + +You can **read items**. + +## Users + +You will be able to: + +* **Create users** (_not implemented_). +* **Read users** (_not implemented_). +""" + +app = FastAPI( + title="ChimichangApp", + description=description, + summary="Deadpool's favorite app. Nuff said.", + version="0.0.1", + terms_of_service="http://example.com/terms/", + contact={ + "name": "Deadpoolio the Amazing", + "url": "http://x-force.example.com/contact/", + "email": "dp@x-force.example.com", + }, + license_info={ + "name": "Apache 2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0.html", + }, +) + + +@app.get("/items/") +async def read_items(): + return [{"name": "Katana"}] diff --git a/docs_src/metadata/tutorial002_py310.py b/docs_src/metadata/tutorial002_py310.py new file mode 100644 index 000000000..cf9ed7087 --- /dev/null +++ b/docs_src/metadata/tutorial002_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI(openapi_url="/api/v1/openapi.json") + + +@app.get("/items/") +async def read_items(): + return [{"name": "Foo"}] diff --git a/docs_src/metadata/tutorial003_py310.py b/docs_src/metadata/tutorial003_py310.py new file mode 100644 index 000000000..ee09c7f37 --- /dev/null +++ b/docs_src/metadata/tutorial003_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI(docs_url="/documentation", redoc_url=None) + + +@app.get("/items/") +async def read_items(): + return [{"name": "Foo"}] diff --git a/docs_src/metadata/tutorial004_py310.py b/docs_src/metadata/tutorial004_py310.py new file mode 100644 index 000000000..465bd659d --- /dev/null +++ b/docs_src/metadata/tutorial004_py310.py @@ -0,0 +1,28 @@ +from fastapi import FastAPI + +tags_metadata = [ + { + "name": "users", + "description": "Operations with users. The **login** logic is also here.", + }, + { + "name": "items", + "description": "Manage items. So _fancy_ they have their own docs.", + "externalDocs": { + "description": "Items external docs", + "url": "https://fastapi.tiangolo.com/", + }, + }, +] + +app = FastAPI(openapi_tags=tags_metadata) + + +@app.get("/users/", tags=["users"]) +async def get_users(): + return [{"name": "Harry"}, {"name": "Ron"}] + + +@app.get("/items/", tags=["items"]) +async def get_items(): + return [{"name": "wand"}, {"name": "flying broom"}] diff --git a/docs_src/middleware/tutorial001_py310.py b/docs_src/middleware/tutorial001_py310.py new file mode 100644 index 000000000..e65a7dade --- /dev/null +++ b/docs_src/middleware/tutorial001_py310.py @@ -0,0 +1,14 @@ +import time + +from fastapi import FastAPI, Request + +app = FastAPI() + + +@app.middleware("http") +async def add_process_time_header(request: Request, call_next): + start_time = time.perf_counter() + response = await call_next(request) + process_time = time.perf_counter() - start_time + response.headers["X-Process-Time"] = str(process_time) + return response diff --git a/docs_src/openapi_callbacks/tutorial001_py39.py b/docs_src/openapi_callbacks/tutorial001_py39.py deleted file mode 100644 index 3f1bac6e2..000000000 --- a/docs_src/openapi_callbacks/tutorial001_py39.py +++ /dev/null @@ -1,53 +0,0 @@ -from typing import Union - -from fastapi import APIRouter, FastAPI -from pydantic import BaseModel, HttpUrl - -app = FastAPI() - - -class Invoice(BaseModel): - id: str - title: Union[str, None] = None - customer: str - total: float - - -class InvoiceEvent(BaseModel): - description: str - paid: bool - - -class InvoiceEventReceived(BaseModel): - ok: bool - - -invoices_callback_router = APIRouter() - - -@invoices_callback_router.post( - "{$callback_url}/invoices/{$request.body.id}", response_model=InvoiceEventReceived -) -def invoice_notification(body: InvoiceEvent): - pass - - -@app.post("/invoices/", callbacks=invoices_callback_router.routes) -def create_invoice(invoice: Invoice, callback_url: Union[HttpUrl, None] = None): - """ - Create an invoice. - - This will (let's imagine) let the API user (some external developer) create an - invoice. - - And this path operation will: - - * Send the invoice to the client. - * Collect the money from the client. - * Send a notification back to the API user (the external developer), as a callback. - * At this point is that the API will somehow send a POST request to the - external API with the notification of the invoice event - (e.g. "payment successful"). - """ - # Send the invoice, collect the money, send the notification (the callback) - return {"msg": "Invoice received"} diff --git a/docs_src/openapi_webhooks/tutorial001_py310.py b/docs_src/openapi_webhooks/tutorial001_py310.py new file mode 100644 index 000000000..55822bb48 --- /dev/null +++ b/docs_src/openapi_webhooks/tutorial001_py310.py @@ -0,0 +1,25 @@ +from datetime import datetime + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Subscription(BaseModel): + username: str + monthly_fee: float + start_date: datetime + + +@app.webhooks.post("new-subscription") +def new_subscription(body: Subscription): + """ + When a new user subscribes to your service we'll send you a POST request with this + data to the URL that you register for the event `new-subscription` in the dashboard. + """ + + +@app.get("/users/") +def read_users(): + return ["Rick", "Morty"] diff --git a/docs_src/path_operation_advanced_configuration/tutorial001_py310.py b/docs_src/path_operation_advanced_configuration/tutorial001_py310.py new file mode 100644 index 000000000..fafa8ffb8 --- /dev/null +++ b/docs_src/path_operation_advanced_configuration/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/", operation_id="some_specific_id_you_define") +async def read_items(): + return [{"item_id": "Foo"}] diff --git a/docs_src/path_operation_advanced_configuration/tutorial002_py310.py b/docs_src/path_operation_advanced_configuration/tutorial002_py310.py new file mode 100644 index 000000000..3aaae9b37 --- /dev/null +++ b/docs_src/path_operation_advanced_configuration/tutorial002_py310.py @@ -0,0 +1,24 @@ +from fastapi import FastAPI +from fastapi.routing import APIRoute + +app = FastAPI() + + +@app.get("/items/") +async def read_items(): + return [{"item_id": "Foo"}] + + +def use_route_names_as_operation_ids(app: FastAPI) -> None: + """ + Simplify operation IDs so that generated API clients have simpler function + names. + + Should be called only after all routes have been added. + """ + for route in app.routes: + if isinstance(route, APIRoute): + route.operation_id = route.name # in this case, 'read_items' + + +use_route_names_as_operation_ids(app) diff --git a/docs_src/path_operation_advanced_configuration/tutorial003_py310.py b/docs_src/path_operation_advanced_configuration/tutorial003_py310.py new file mode 100644 index 000000000..dcc358e32 --- /dev/null +++ b/docs_src/path_operation_advanced_configuration/tutorial003_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/", include_in_schema=False) +async def read_items(): + return [{"item_id": "Foo"}] diff --git a/docs_src/path_operation_advanced_configuration/tutorial004_py39.py b/docs_src/path_operation_advanced_configuration/tutorial004_py39.py deleted file mode 100644 index 8fabe7cb8..000000000 --- a/docs_src/path_operation_advanced_configuration/tutorial004_py39.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - - -@app.post("/items/", summary="Create an item") -async def create_item(item: Item) -> Item: - """ - 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 - \f - :param item: User input. - """ - return item diff --git a/docs_src/path_operation_advanced_configuration/tutorial005_py310.py b/docs_src/path_operation_advanced_configuration/tutorial005_py310.py new file mode 100644 index 000000000..5837ad835 --- /dev/null +++ b/docs_src/path_operation_advanced_configuration/tutorial005_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/", openapi_extra={"x-aperture-labs-portal": "blue"}) +async def read_items(): + return [{"item_id": "portal-gun"}] diff --git a/docs_src/path_operation_advanced_configuration/tutorial006_py310.py b/docs_src/path_operation_advanced_configuration/tutorial006_py310.py new file mode 100644 index 000000000..403c3ee3f --- /dev/null +++ b/docs_src/path_operation_advanced_configuration/tutorial006_py310.py @@ -0,0 +1,41 @@ +from fastapi import FastAPI, Request + +app = FastAPI() + + +def magic_data_reader(raw_body: bytes): + return { + "size": len(raw_body), + "content": { + "name": "Maaaagic", + "price": 42, + "description": "Just kiddin', no magic here. ✨", + }, + } + + +@app.post( + "/items/", + openapi_extra={ + "requestBody": { + "content": { + "application/json": { + "schema": { + "required": ["name", "price"], + "type": "object", + "properties": { + "name": {"type": "string"}, + "price": {"type": "number"}, + "description": {"type": "string"}, + }, + } + } + }, + "required": True, + }, + }, +) +async def create_item(request: Request): + raw_body = await request.body() + data = magic_data_reader(raw_body) + return data diff --git a/docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py b/docs_src/path_operation_advanced_configuration/tutorial007_py310.py similarity index 68% rename from docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py rename to docs_src/path_operation_advanced_configuration/tutorial007_py310.py index 849f648e1..ff64ef792 100644 --- a/docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py +++ b/docs_src/path_operation_advanced_configuration/tutorial007_py310.py @@ -1,6 +1,6 @@ import yaml from fastapi import FastAPI, HTTPException, Request -from pydantic.v1 import BaseModel, ValidationError +from pydantic import BaseModel, ValidationError app = FastAPI() @@ -14,7 +14,7 @@ class Item(BaseModel): "/items/", openapi_extra={ "requestBody": { - "content": {"application/x-yaml": {"schema": Item.schema()}}, + "content": {"application/x-yaml": {"schema": Item.model_json_schema()}}, "required": True, }, }, @@ -26,7 +26,7 @@ async def create_item(request: Request): except yaml.YAMLError: raise HTTPException(status_code=422, detail="Invalid YAML") try: - item = Item.parse_obj(data) + item = Item.model_validate(data) except ValidationError as e: - raise HTTPException(status_code=422, detail=e.errors()) + raise HTTPException(status_code=422, detail=e.errors(include_url=False)) return item diff --git a/docs_src/path_operation_configuration/tutorial001_py39.py b/docs_src/path_operation_configuration/tutorial001_py39.py deleted file mode 100644 index 09b318282..000000000 --- a/docs_src/path_operation_configuration/tutorial001_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, status -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - - -@app.post("/items/", status_code=status.HTTP_201_CREATED) -async def create_item(item: Item) -> Item: - return item diff --git a/docs_src/path_operation_configuration/tutorial002_py39.py b/docs_src/path_operation_configuration/tutorial002_py39.py deleted file mode 100644 index fca3b0de9..000000000 --- a/docs_src/path_operation_configuration/tutorial002_py39.py +++ /dev/null @@ -1,29 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - - -@app.post("/items/", tags=["items"]) -async def create_item(item: Item) -> Item: - return item - - -@app.get("/items/", tags=["items"]) -async def read_items(): - return [{"name": "Foo", "price": 42}] - - -@app.get("/users/", tags=["users"]) -async def read_users(): - return [{"username": "johndoe"}] diff --git a/docs_src/path_operation_configuration/tutorial002b_py310.py b/docs_src/path_operation_configuration/tutorial002b_py310.py new file mode 100644 index 000000000..d53b4d817 --- /dev/null +++ b/docs_src/path_operation_configuration/tutorial002b_py310.py @@ -0,0 +1,20 @@ +from enum import Enum + +from fastapi import FastAPI + +app = FastAPI() + + +class Tags(Enum): + items = "items" + users = "users" + + +@app.get("/items/", tags=[Tags.items]) +async def get_items(): + return ["Portal gun", "Plumbus"] + + +@app.get("/users/", tags=[Tags.users]) +async def read_users(): + return ["Rick", "Morty"] diff --git a/docs_src/path_operation_configuration/tutorial003_py39.py b/docs_src/path_operation_configuration/tutorial003_py39.py deleted file mode 100644 index a77fb34d8..000000000 --- a/docs_src/path_operation_configuration/tutorial003_py39.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - - -@app.post( - "/items/", - summary="Create an item", - description="Create an item with all the information, name, description, price, tax and a set of unique tags", -) -async def create_item(item: Item) -> Item: - return item diff --git a/docs_src/path_operation_configuration/tutorial004_py39.py b/docs_src/path_operation_configuration/tutorial004_py39.py deleted file mode 100644 index 31dfbff1d..000000000 --- a/docs_src/path_operation_configuration/tutorial004_py39.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - - -@app.post("/items/", summary="Create an item") -async def create_item(item: Item) -> Item: - """ - 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 - """ - return item diff --git a/docs_src/path_operation_configuration/tutorial005_py39.py b/docs_src/path_operation_configuration/tutorial005_py39.py deleted file mode 100644 index 0a53a8f2d..000000000 --- a/docs_src/path_operation_configuration/tutorial005_py39.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: set[str] = set() - - -@app.post( - "/items/", - summary="Create an item", - response_description="The created item", -) -async def create_item(item: Item) -> Item: - """ - 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 - """ - return item diff --git a/docs_src/path_operation_configuration/tutorial006_py310.py b/docs_src/path_operation_configuration/tutorial006_py310.py new file mode 100644 index 000000000..7c1aa9b20 --- /dev/null +++ b/docs_src/path_operation_configuration/tutorial006_py310.py @@ -0,0 +1,18 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/", tags=["items"]) +async def read_items(): + return [{"name": "Foo", "price": 42}] + + +@app.get("/users/", tags=["users"]) +async def read_users(): + return [{"username": "johndoe"}] + + +@app.get("/elements/", tags=["items"], deprecated=True) +async def read_elements(): + return [{"item_id": "Foo"}] diff --git a/docs_src/path_params/tutorial001_py310.py b/docs_src/path_params/tutorial001_py310.py new file mode 100644 index 000000000..7bbf70e6c --- /dev/null +++ b/docs_src/path_params/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_item(item_id): + return {"item_id": item_id} diff --git a/docs_src/path_params/tutorial002_py310.py b/docs_src/path_params/tutorial002_py310.py new file mode 100644 index 000000000..8272ad70d --- /dev/null +++ b/docs_src/path_params/tutorial002_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_item(item_id: int): + return {"item_id": item_id} diff --git a/docs_src/path_params/tutorial003_py310.py b/docs_src/path_params/tutorial003_py310.py new file mode 100644 index 000000000..5f0aa0923 --- /dev/null +++ b/docs_src/path_params/tutorial003_py310.py @@ -0,0 +1,13 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/users/me") +async def read_user_me(): + return {"user_id": "the current user"} + + +@app.get("/users/{user_id}") +async def read_user(user_id: str): + return {"user_id": user_id} diff --git a/docs_src/path_params/tutorial003b_py310.py b/docs_src/path_params/tutorial003b_py310.py new file mode 100644 index 000000000..822d37369 --- /dev/null +++ b/docs_src/path_params/tutorial003b_py310.py @@ -0,0 +1,13 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/users") +async def read_users(): + return ["Rick", "Morty"] + + +@app.get("/users") +async def read_users2(): + return ["Bean", "Elfo"] diff --git a/docs_src/path_params/tutorial004_py310.py b/docs_src/path_params/tutorial004_py310.py new file mode 100644 index 000000000..2961e6178 --- /dev/null +++ b/docs_src/path_params/tutorial004_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/files/{file_path:path}") +async def read_file(file_path: str): + return {"file_path": file_path} diff --git a/docs_src/path_params/tutorial005_py310.py b/docs_src/path_params/tutorial005_py310.py new file mode 100644 index 000000000..9a24a4963 --- /dev/null +++ b/docs_src/path_params/tutorial005_py310.py @@ -0,0 +1,23 @@ +from enum import Enum + +from fastapi import FastAPI + + +class ModelName(str, Enum): + alexnet = "alexnet" + resnet = "resnet" + lenet = "lenet" + + +app = FastAPI() + + +@app.get("/models/{model_name}") +async def get_model(model_name: ModelName): + if model_name is ModelName.alexnet: + return {"model_name": model_name, "message": "Deep Learning FTW!"} + + if model_name.value == "lenet": + return {"model_name": model_name, "message": "LeCNN all the images"} + + return {"model_name": model_name, "message": "Have some residuals"} diff --git a/docs_src/path_params_numeric_validations/tutorial002_an_py310.py b/docs_src/path_params_numeric_validations/tutorial002_an_py310.py new file mode 100644 index 000000000..cd882abb2 --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial002_an_py310.py @@ -0,0 +1,15 @@ +from typing import Annotated + +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items( + q: str, item_id: Annotated[int, Path(title="The ID of the item to get")] +): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial002_py310.py b/docs_src/path_params_numeric_validations/tutorial002_py310.py new file mode 100644 index 000000000..63ac691a8 --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial002_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items(q: str, item_id: int = Path(title="The ID of the item to get")): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial003_an_py310.py b/docs_src/path_params_numeric_validations/tutorial003_an_py310.py new file mode 100644 index 000000000..1588556e7 --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial003_an_py310.py @@ -0,0 +1,15 @@ +from typing import Annotated + +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items( + item_id: Annotated[int, Path(title="The ID of the item to get")], q: str +): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial003_py310.py b/docs_src/path_params_numeric_validations/tutorial003_py310.py new file mode 100644 index 000000000..8df0ffc62 --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial003_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items(*, item_id: int = Path(title="The ID of the item to get"), q: str): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial004_an_py310.py b/docs_src/path_params_numeric_validations/tutorial004_an_py310.py new file mode 100644 index 000000000..f67f6450e --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial004_an_py310.py @@ -0,0 +1,15 @@ +from typing import Annotated + +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items( + item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)], q: str +): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial004_py310.py b/docs_src/path_params_numeric_validations/tutorial004_py310.py new file mode 100644 index 000000000..86651d47c --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial004_py310.py @@ -0,0 +1,13 @@ +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items( + *, item_id: int = Path(title="The ID of the item to get", ge=1), q: str +): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial005_an_py310.py b/docs_src/path_params_numeric_validations/tutorial005_an_py310.py new file mode 100644 index 000000000..571dd583c --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial005_an_py310.py @@ -0,0 +1,16 @@ +from typing import Annotated + +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items( + item_id: Annotated[int, Path(title="The ID of the item to get", gt=0, le=1000)], + q: str, +): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial005_py310.py b/docs_src/path_params_numeric_validations/tutorial005_py310.py new file mode 100644 index 000000000..8f12f2da0 --- /dev/null +++ b/docs_src/path_params_numeric_validations/tutorial005_py310.py @@ -0,0 +1,15 @@ +from fastapi import FastAPI, Path + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_items( + *, + item_id: int = Path(title="The ID of the item to get", gt=0, le=1000), + q: str, +): + results = {"item_id": item_id} + if q: + results.update({"q": q}) + return results diff --git a/docs_src/path_params_numeric_validations/tutorial001_an_py39.py b/docs_src/path_params_numeric_validations/tutorial006_an_py310.py similarity index 61% rename from docs_src/path_params_numeric_validations/tutorial001_an_py39.py rename to docs_src/path_params_numeric_validations/tutorial006_an_py310.py index b36315a46..426ec3776 100644 --- a/docs_src/path_params_numeric_validations/tutorial001_an_py39.py +++ b/docs_src/path_params_numeric_validations/tutorial006_an_py310.py @@ -1,4 +1,4 @@ -from typing import Annotated, Union +from typing import Annotated from fastapi import FastAPI, Path, Query @@ -7,10 +7,14 @@ app = FastAPI() @app.get("/items/{item_id}") async def read_items( - item_id: Annotated[int, Path(title="The ID of the item to get")], - q: Annotated[Union[str, None], Query(alias="item-query")] = None, + *, + item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)], + q: str, + size: Annotated[float, Query(gt=0, lt=10.5)], ): results = {"item_id": item_id} if q: results.update({"q": q}) + if size: + results.update({"size": size}) return results diff --git a/docs_src/path_params_numeric_validations/tutorial001_py39.py b/docs_src/path_params_numeric_validations/tutorial006_py310.py similarity index 53% rename from docs_src/path_params_numeric_validations/tutorial001_py39.py rename to docs_src/path_params_numeric_validations/tutorial006_py310.py index 530147028..f07629aa0 100644 --- a/docs_src/path_params_numeric_validations/tutorial001_py39.py +++ b/docs_src/path_params_numeric_validations/tutorial006_py310.py @@ -1,5 +1,3 @@ -from typing import Union - from fastapi import FastAPI, Path, Query app = FastAPI() @@ -7,10 +5,14 @@ app = FastAPI() @app.get("/items/{item_id}") async def read_items( - item_id: int = Path(title="The ID of the item to get"), - q: Union[str, None] = Query(default=None, alias="item-query"), + *, + item_id: int = Path(title="The ID of the item to get", ge=0, le=1000), + q: str, + size: float = Query(gt=0, lt=10.5), ): results = {"item_id": item_id} if q: results.update({"q": q}) + if size: + results.update({"size": size}) return results diff --git a/docs_src/pydantic_v1_in_v2/tutorial001_an_py39.py b/docs_src/pydantic_v1_in_v2/tutorial001_an_py39.py deleted file mode 100644 index 62a4b2c21..000000000 --- a/docs_src/pydantic_v1_in_v2/tutorial001_an_py39.py +++ /dev/null @@ -1,9 +0,0 @@ -from typing import Union - -from pydantic.v1 import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - size: float diff --git a/docs_src/pydantic_v1_in_v2/tutorial002_an_py39.py b/docs_src/pydantic_v1_in_v2/tutorial002_an_py39.py deleted file mode 100644 index 3c6a06080..000000000 --- a/docs_src/pydantic_v1_in_v2/tutorial002_an_py39.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic.v1 import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - size: float - - -app = FastAPI() - - -@app.post("/items/") -async def create_item(item: Item) -> Item: - return item diff --git a/docs_src/pydantic_v1_in_v2/tutorial003_an_py39.py b/docs_src/pydantic_v1_in_v2/tutorial003_an_py39.py deleted file mode 100644 index 117d6f7a4..000000000 --- a/docs_src/pydantic_v1_in_v2/tutorial003_an_py39.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel as BaseModelV2 -from pydantic.v1 import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - size: float - - -class ItemV2(BaseModelV2): - name: str - description: Union[str, None] = None - size: float - - -app = FastAPI() - - -@app.post("/items/", response_model=ItemV2) -async def create_item(item: Item): - return item diff --git a/docs_src/pydantic_v1_in_v2/tutorial004_an_py39.py b/docs_src/pydantic_v1_in_v2/tutorial004_an_py39.py deleted file mode 100644 index 150ab20ae..000000000 --- a/docs_src/pydantic_v1_in_v2/tutorial004_an_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI -from fastapi.temp_pydantic_v1_params import Body -from pydantic.v1 import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - size: float - - -app = FastAPI() - - -@app.post("/items/") -async def create_item(item: Annotated[Item, Body(embed=True)]) -> Item: - return item diff --git a/docs_src/python_types/tutorial001_py310.py b/docs_src/python_types/tutorial001_py310.py new file mode 100644 index 000000000..09039435f --- /dev/null +++ b/docs_src/python_types/tutorial001_py310.py @@ -0,0 +1,6 @@ +def get_full_name(first_name, last_name): + full_name = first_name.title() + " " + last_name.title() + return full_name + + +print(get_full_name("john", "doe")) diff --git a/docs_src/python_types/tutorial002_py310.py b/docs_src/python_types/tutorial002_py310.py new file mode 100644 index 000000000..c0857a116 --- /dev/null +++ b/docs_src/python_types/tutorial002_py310.py @@ -0,0 +1,6 @@ +def get_full_name(first_name: str, last_name: str): + full_name = first_name.title() + " " + last_name.title() + return full_name + + +print(get_full_name("john", "doe")) diff --git a/docs_src/python_types/tutorial003_py310.py b/docs_src/python_types/tutorial003_py310.py new file mode 100644 index 000000000..d021d8211 --- /dev/null +++ b/docs_src/python_types/tutorial003_py310.py @@ -0,0 +1,3 @@ +def get_name_with_age(name: str, age: int): + name_with_age = name + " is this old: " + age + return name_with_age diff --git a/docs_src/python_types/tutorial004_py310.py b/docs_src/python_types/tutorial004_py310.py new file mode 100644 index 000000000..9400269e2 --- /dev/null +++ b/docs_src/python_types/tutorial004_py310.py @@ -0,0 +1,3 @@ +def get_name_with_age(name: str, age: int): + name_with_age = name + " is this old: " + str(age) + return name_with_age diff --git a/docs_src/python_types/tutorial005_py310.py b/docs_src/python_types/tutorial005_py310.py new file mode 100644 index 000000000..6c8edb0ec --- /dev/null +++ b/docs_src/python_types/tutorial005_py310.py @@ -0,0 +1,2 @@ +def get_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes): + return item_a, item_b, item_c, item_d, item_e diff --git a/docs_src/python_types/tutorial006_py310.py b/docs_src/python_types/tutorial006_py310.py new file mode 100644 index 000000000..486b67caf --- /dev/null +++ b/docs_src/python_types/tutorial006_py310.py @@ -0,0 +1,3 @@ +def process_items(items: list[str]): + for item in items: + print(item) diff --git a/docs_src/python_types/tutorial007_py310.py b/docs_src/python_types/tutorial007_py310.py new file mode 100644 index 000000000..ea96c7964 --- /dev/null +++ b/docs_src/python_types/tutorial007_py310.py @@ -0,0 +1,2 @@ +def process_items(items_t: tuple[int, int, str], items_s: set[bytes]): + return items_t, items_s diff --git a/docs_src/python_types/tutorial008_py310.py b/docs_src/python_types/tutorial008_py310.py new file mode 100644 index 000000000..a393385b0 --- /dev/null +++ b/docs_src/python_types/tutorial008_py310.py @@ -0,0 +1,4 @@ +def process_items(prices: dict[str, float]): + for item_name, item_price in prices.items(): + print(item_name) + print(item_price) diff --git a/docs_src/python_types/tutorial010_py310.py b/docs_src/python_types/tutorial010_py310.py new file mode 100644 index 000000000..468cffc2d --- /dev/null +++ b/docs_src/python_types/tutorial010_py310.py @@ -0,0 +1,7 @@ +class Person: + def __init__(self, name: str): + self.name = name + + +def get_person_name(one_person: Person): + return one_person.name diff --git a/docs_src/python_types/tutorial011_py39.py b/docs_src/python_types/tutorial011_py39.py deleted file mode 100644 index 4eb40b405..000000000 --- a/docs_src/python_types/tutorial011_py39.py +++ /dev/null @@ -1,23 +0,0 @@ -from datetime import datetime -from typing import Union - -from pydantic import BaseModel - - -class User(BaseModel): - id: int - name: str = "John Doe" - signup_ts: Union[datetime, None] = None - friends: list[int] = [] - - -external_data = { - "id": "123", - "signup_ts": "2017-06-01 12:22", - "friends": [1, "2", b"3"], -} -user = User(**external_data) -print(user) -# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3] -print(user.id) -# > 123 diff --git a/docs_src/python_types/tutorial012_py39.py b/docs_src/python_types/tutorial012_py39.py deleted file mode 100644 index 74fa94c43..000000000 --- a/docs_src/python_types/tutorial012_py39.py +++ /dev/null @@ -1,8 +0,0 @@ -from typing import Optional - -from pydantic import BaseModel - - -class User(BaseModel): - name: str - age: Optional[int] diff --git a/docs_src/python_types/tutorial013_py310.py b/docs_src/python_types/tutorial013_py310.py new file mode 100644 index 000000000..65a0eaa93 --- /dev/null +++ b/docs_src/python_types/tutorial013_py310.py @@ -0,0 +1,5 @@ +from typing import Annotated + + +def say_hello(name: Annotated[str, "this is just metadata"]) -> str: + return f"Hello {name}" diff --git a/docs_src/query_param_models/tutorial001_an_py39.py b/docs_src/query_param_models/tutorial001_an_py39.py deleted file mode 100644 index 71427acae..000000000 --- a/docs_src/query_param_models/tutorial001_an_py39.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Annotated, Literal - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field - -app = FastAPI() - - -class FilterParams(BaseModel): - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: list[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: Annotated[FilterParams, Query()]): - return filter_query diff --git a/docs_src/query_param_models/tutorial001_py39.py b/docs_src/query_param_models/tutorial001_py39.py deleted file mode 100644 index 3ebf9f4d7..000000000 --- a/docs_src/query_param_models/tutorial001_py39.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Literal - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field - -app = FastAPI() - - -class FilterParams(BaseModel): - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: list[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: FilterParams = Query()): - return filter_query diff --git a/docs_src/query_param_models/tutorial002_an_py39.py b/docs_src/query_param_models/tutorial002_an_py39.py deleted file mode 100644 index 975956502..000000000 --- a/docs_src/query_param_models/tutorial002_an_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Annotated, Literal - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field - -app = FastAPI() - - -class FilterParams(BaseModel): - model_config = {"extra": "forbid"} - - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: list[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: Annotated[FilterParams, Query()]): - return filter_query diff --git a/docs_src/query_param_models/tutorial002_py39.py b/docs_src/query_param_models/tutorial002_py39.py deleted file mode 100644 index 6ec418499..000000000 --- a/docs_src/query_param_models/tutorial002_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Literal - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field - -app = FastAPI() - - -class FilterParams(BaseModel): - model_config = {"extra": "forbid"} - - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: list[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: FilterParams = Query()): - return filter_query diff --git a/docs_src/query_params/tutorial001_py310.py b/docs_src/query_params/tutorial001_py310.py new file mode 100644 index 000000000..74e1a1760 --- /dev/null +++ b/docs_src/query_params/tutorial001_py310.py @@ -0,0 +1,10 @@ +from fastapi import FastAPI + +app = FastAPI() + +fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] + + +@app.get("/items/") +async def read_item(skip: int = 0, limit: int = 10): + return fake_items_db[skip : skip + limit] diff --git a/docs_src/query_params/tutorial002_py39.py b/docs_src/query_params/tutorial002_py39.py deleted file mode 100644 index 8465f45ee..000000000 --- a/docs_src/query_params/tutorial002_py39.py +++ /dev/null @@ -1,12 +0,0 @@ -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/items/{item_id}") -async def read_item(item_id: str, q: Union[str, None] = None): - if q: - return {"item_id": item_id, "q": q} - return {"item_id": item_id} diff --git a/docs_src/query_params/tutorial003_py39.py b/docs_src/query_params/tutorial003_py39.py deleted file mode 100644 index 3362715b3..000000000 --- a/docs_src/query_params/tutorial003_py39.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/items/{item_id}") -async def read_item(item_id: str, q: Union[str, None] = None, short: bool = False): - item = {"item_id": item_id} - if q: - item.update({"q": q}) - if not short: - item.update( - {"description": "This is an amazing item that has a long description"} - ) - return item diff --git a/docs_src/query_params/tutorial004_py39.py b/docs_src/query_params/tutorial004_py39.py deleted file mode 100644 index 049c3ae93..000000000 --- a/docs_src/query_params/tutorial004_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/users/{user_id}/items/{item_id}") -async def read_user_item( - user_id: int, item_id: str, q: Union[str, None] = None, short: bool = False -): - item = {"item_id": item_id, "owner_id": user_id} - if q: - item.update({"q": q}) - if not short: - item.update( - {"description": "This is an amazing item that has a long description"} - ) - return item diff --git a/docs_src/query_params/tutorial005_py310.py b/docs_src/query_params/tutorial005_py310.py new file mode 100644 index 000000000..e16a40574 --- /dev/null +++ b/docs_src/query_params/tutorial005_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/items/{item_id}") +async def read_user_item(item_id: str, needy: str): + item = {"item_id": item_id, "needy": needy} + return item diff --git a/docs_src/query_params/tutorial006_py39.py b/docs_src/query_params/tutorial006_py39.py deleted file mode 100644 index f0dbfe08f..000000000 --- a/docs_src/query_params/tutorial006_py39.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/items/{item_id}") -async def read_user_item( - item_id: str, needy: str, skip: int = 0, limit: Union[int, None] = None -): - item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit} - return item diff --git a/docs_src/query_params_str_validations/tutorial001_py39.py b/docs_src/query_params_str_validations/tutorial001_py39.py deleted file mode 100644 index e38326b18..000000000 --- a/docs_src/query_params_str_validations/tutorial001_py39.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/items/") -async def read_items(q: Union[str, None] = None): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial002_an_py39.py b/docs_src/query_params_str_validations/tutorial002_an_py39.py deleted file mode 100644 index 2d8fc9798..000000000 --- a/docs_src/query_params_str_validations/tutorial002_an_py39.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items(q: Annotated[Union[str, None], Query(max_length=50)] = None): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial003_an_py39.py b/docs_src/query_params_str_validations/tutorial003_an_py39.py deleted file mode 100644 index 3d6697793..000000000 --- a/docs_src/query_params_str_validations/tutorial003_an_py39.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[Union[str, None], Query(min_length=3, max_length=50)] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial003_py39.py b/docs_src/query_params_str_validations/tutorial003_py39.py deleted file mode 100644 index 7d4917373..000000000 --- a/docs_src/query_params_str_validations/tutorial003_py39.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Union[str, None] = Query(default=None, min_length=3, max_length=50), -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial004_an_py39.py b/docs_src/query_params_str_validations/tutorial004_an_py39.py deleted file mode 100644 index de27097b3..000000000 --- a/docs_src/query_params_str_validations/tutorial004_an_py39.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[ - Union[str, None], Query(min_length=3, max_length=50, pattern="^fixedquery$") - ] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial004_py39.py b/docs_src/query_params_str_validations/tutorial004_py39.py deleted file mode 100644 index 64a647a16..000000000 --- a/docs_src/query_params_str_validations/tutorial004_py39.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Union[str, None] = Query( - default=None, min_length=3, max_length=50, pattern="^fixedquery$" - ), -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial004_regex_an_py310.py b/docs_src/query_params_str_validations/tutorial004_regex_an_py310.py deleted file mode 100644 index 21e0d3eb8..000000000 --- a/docs_src/query_params_str_validations/tutorial004_regex_an_py310.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Annotated - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[ - str | None, Query(min_length=3, max_length=50, regex="^fixedquery$") - ] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial002_py39.py b/docs_src/query_params_str_validations/tutorial005_an_py310.py similarity index 65% rename from docs_src/query_params_str_validations/tutorial002_py39.py rename to docs_src/query_params_str_validations/tutorial005_an_py310.py index 17e017b7e..b1f6046b5 100644 --- a/docs_src/query_params_str_validations/tutorial002_py39.py +++ b/docs_src/query_params_str_validations/tutorial005_an_py310.py @@ -1,4 +1,4 @@ -from typing import Union +from typing import Annotated from fastapi import FastAPI, Query @@ -6,7 +6,7 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: Union[str, None] = Query(default=None, max_length=50)): +async def read_items(q: Annotated[str, Query(min_length=3)] = "fixedquery"): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial009_py39.py b/docs_src/query_params_str_validations/tutorial005_py310.py similarity index 64% rename from docs_src/query_params_str_validations/tutorial009_py39.py rename to docs_src/query_params_str_validations/tutorial005_py310.py index 8a6bfe2d9..8ab42869e 100644 --- a/docs_src/query_params_str_validations/tutorial009_py39.py +++ b/docs_src/query_params_str_validations/tutorial005_py310.py @@ -1,12 +1,10 @@ -from typing import Union - from fastapi import FastAPI, Query app = FastAPI() @app.get("/items/") -async def read_items(q: Union[str, None] = Query(default=None, alias="item-query")): +async def read_items(q: str = Query(default="fixedquery", min_length=3)): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial006c_py39.py b/docs_src/query_params_str_validations/tutorial006_an_py310.py similarity index 69% rename from docs_src/query_params_str_validations/tutorial006c_py39.py rename to docs_src/query_params_str_validations/tutorial006_an_py310.py index 0a0e820da..3b4a676d2 100644 --- a/docs_src/query_params_str_validations/tutorial006c_py39.py +++ b/docs_src/query_params_str_validations/tutorial006_an_py310.py @@ -1,4 +1,4 @@ -from typing import Union +from typing import Annotated from fastapi import FastAPI, Query @@ -6,7 +6,7 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: Union[str, None] = Query(min_length=3)): +async def read_items(q: Annotated[str, Query(min_length=3)]): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial006c_an_py39.py b/docs_src/query_params_str_validations/tutorial006_py310.py similarity index 64% rename from docs_src/query_params_str_validations/tutorial006c_an_py39.py rename to docs_src/query_params_str_validations/tutorial006_py310.py index 76a1cd49a..9a90eb64e 100644 --- a/docs_src/query_params_str_validations/tutorial006c_an_py39.py +++ b/docs_src/query_params_str_validations/tutorial006_py310.py @@ -1,12 +1,10 @@ -from typing import Annotated, Union - from fastapi import FastAPI, Query app = FastAPI() @app.get("/items/") -async def read_items(q: Annotated[Union[str, None], Query(min_length=3)]): +async def read_items(q: str = Query(min_length=3)): results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} if q: results.update({"q": q}) diff --git a/docs_src/query_params_str_validations/tutorial007_an_py39.py b/docs_src/query_params_str_validations/tutorial007_an_py39.py deleted file mode 100644 index 8d7a82c46..000000000 --- a/docs_src/query_params_str_validations/tutorial007_an_py39.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[Union[str, None], Query(title="Query string", min_length=3)] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial007_py39.py b/docs_src/query_params_str_validations/tutorial007_py39.py deleted file mode 100644 index 27b649e14..000000000 --- a/docs_src/query_params_str_validations/tutorial007_py39.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Union[str, None] = Query(default=None, title="Query string", min_length=3), -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial008_an_py39.py b/docs_src/query_params_str_validations/tutorial008_an_py39.py deleted file mode 100644 index f3f2f2c0e..000000000 --- a/docs_src/query_params_str_validations/tutorial008_an_py39.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[ - Union[str, None], - Query( - title="Query string", - description="Query string for the items to search in the database that have a good match", - min_length=3, - ), - ] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial008_py39.py b/docs_src/query_params_str_validations/tutorial008_py39.py deleted file mode 100644 index e3e0b50aa..000000000 --- a/docs_src/query_params_str_validations/tutorial008_py39.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Union[str, None] = Query( - default=None, - title="Query string", - description="Query string for the items to search in the database that have a good match", - min_length=3, - ), -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial009_an_py39.py b/docs_src/query_params_str_validations/tutorial009_an_py39.py deleted file mode 100644 index 70a89e613..000000000 --- a/docs_src/query_params_str_validations/tutorial009_an_py39.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items(q: Annotated[Union[str, None], Query(alias="item-query")] = None): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial010_an_py39.py b/docs_src/query_params_str_validations/tutorial010_an_py39.py deleted file mode 100644 index b126c116f..000000000 --- a/docs_src/query_params_str_validations/tutorial010_an_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[ - Union[str, None], - Query( - alias="item-query", - title="Query string", - description="Query string for the items to search in the database that have a good match", - min_length=3, - max_length=50, - pattern="^fixedquery$", - deprecated=True, - ), - ] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial010_py39.py b/docs_src/query_params_str_validations/tutorial010_py39.py deleted file mode 100644 index ff29176fe..000000000 --- a/docs_src/query_params_str_validations/tutorial010_py39.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Union[str, None] = Query( - default=None, - alias="item-query", - title="Query string", - description="Query string for the items to search in the database that have a good match", - min_length=3, - max_length=50, - pattern="^fixedquery$", - deprecated=True, - ), -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial011_an_py39.py b/docs_src/query_params_str_validations/tutorial012_an_py310.py similarity index 52% rename from docs_src/query_params_str_validations/tutorial011_an_py39.py rename to docs_src/query_params_str_validations/tutorial012_an_py310.py index 416e3990d..9b5a9c2fb 100644 --- a/docs_src/query_params_str_validations/tutorial011_an_py39.py +++ b/docs_src/query_params_str_validations/tutorial012_an_py310.py @@ -1,4 +1,4 @@ -from typing import Annotated, Union +from typing import Annotated from fastapi import FastAPI, Query @@ -6,6 +6,6 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: Annotated[Union[list[str], None], Query()] = None): +async def read_items(q: Annotated[list[str], Query()] = ["foo", "bar"]): query_items = {"q": q} return query_items diff --git a/docs_src/query_params_str_validations/tutorial012_py310.py b/docs_src/query_params_str_validations/tutorial012_py310.py new file mode 100644 index 000000000..070d0b04b --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial012_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: list[str] = Query(default=["foo", "bar"])): + query_items = {"q": q} + return query_items diff --git a/docs_src/query_params_str_validations/tutorial011_py39.py b/docs_src/query_params_str_validations/tutorial013_an_py310.py similarity index 56% rename from docs_src/query_params_str_validations/tutorial011_py39.py rename to docs_src/query_params_str_validations/tutorial013_an_py310.py index 878f95c79..602734145 100644 --- a/docs_src/query_params_str_validations/tutorial011_py39.py +++ b/docs_src/query_params_str_validations/tutorial013_an_py310.py @@ -1,4 +1,4 @@ -from typing import Union +from typing import Annotated from fastapi import FastAPI, Query @@ -6,6 +6,6 @@ app = FastAPI() @app.get("/items/") -async def read_items(q: Union[list[str], None] = Query(default=None)): +async def read_items(q: Annotated[list, Query()] = []): query_items = {"q": q} return query_items diff --git a/docs_src/query_params_str_validations/tutorial013_py310.py b/docs_src/query_params_str_validations/tutorial013_py310.py new file mode 100644 index 000000000..0b0f44869 --- /dev/null +++ b/docs_src/query_params_str_validations/tutorial013_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI, Query + +app = FastAPI() + + +@app.get("/items/") +async def read_items(q: list = Query(default=[])): + query_items = {"q": q} + return query_items diff --git a/docs_src/query_params_str_validations/tutorial014_an_py39.py b/docs_src/query_params_str_validations/tutorial014_an_py39.py deleted file mode 100644 index aaf7703a5..000000000 --- a/docs_src/query_params_str_validations/tutorial014_an_py39.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - hidden_query: Annotated[Union[str, None], Query(include_in_schema=False)] = None, -): - if hidden_query: - return {"hidden_query": hidden_query} - else: - return {"hidden_query": "Not found"} diff --git a/docs_src/query_params_str_validations/tutorial014_py39.py b/docs_src/query_params_str_validations/tutorial014_py39.py deleted file mode 100644 index 779db1c80..000000000 --- a/docs_src/query_params_str_validations/tutorial014_py39.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - hidden_query: Union[str, None] = Query(default=None, include_in_schema=False), -): - if hidden_query: - return {"hidden_query": hidden_query} - else: - return {"hidden_query": "Not found"} diff --git a/docs_src/query_params_str_validations/tutorial015_an_py39.py b/docs_src/query_params_str_validations/tutorial015_an_py39.py deleted file mode 100644 index 989b6d2c2..000000000 --- a/docs_src/query_params_str_validations/tutorial015_an_py39.py +++ /dev/null @@ -1,30 +0,0 @@ -import random -from typing import Annotated, Union - -from fastapi import FastAPI -from pydantic import AfterValidator - -app = FastAPI() - -data = { - "isbn-9781529046137": "The Hitchhiker's Guide to the Galaxy", - "imdb-tt0371724": "The Hitchhiker's Guide to the Galaxy", - "isbn-9781439512982": "Isaac Asimov: The Complete Stories, Vol. 2", -} - - -def check_valid_id(id: str): - if not id.startswith(("isbn-", "imdb-")): - raise ValueError('Invalid ID format, it must start with "isbn-" or "imdb-"') - return id - - -@app.get("/items/") -async def read_items( - id: Annotated[Union[str, None], AfterValidator(check_valid_id)] = None, -): - if id: - item = data.get(id) - else: - id, item = random.choice(list(data.items())) - return {"id": id, "name": item} diff --git a/docs_src/request_files/tutorial001_02_an_py39.py b/docs_src/request_files/tutorial001_02_an_py39.py deleted file mode 100644 index bb090ff6c..000000000 --- a/docs_src/request_files/tutorial001_02_an_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Annotated, Union - -from fastapi import FastAPI, File, UploadFile - -app = FastAPI() - - -@app.post("/files/") -async def create_file(file: Annotated[Union[bytes, None], File()] = None): - if not file: - return {"message": "No file sent"} - else: - return {"file_size": len(file)} - - -@app.post("/uploadfile/") -async def create_upload_file(file: Union[UploadFile, None] = None): - if not file: - return {"message": "No upload file sent"} - else: - return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001_02_py39.py b/docs_src/request_files/tutorial001_02_py39.py deleted file mode 100644 index ac30be2d3..000000000 --- a/docs_src/request_files/tutorial001_02_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, File, UploadFile - -app = FastAPI() - - -@app.post("/files/") -async def create_file(file: Union[bytes, None] = File(default=None)): - if not file: - return {"message": "No file sent"} - else: - return {"file_size": len(file)} - - -@app.post("/uploadfile/") -async def create_upload_file(file: Union[UploadFile, None] = None): - if not file: - return {"message": "No upload file sent"} - else: - return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001_03_an_py310.py b/docs_src/request_files/tutorial001_03_an_py310.py new file mode 100644 index 000000000..93098a677 --- /dev/null +++ b/docs_src/request_files/tutorial001_03_an_py310.py @@ -0,0 +1,17 @@ +from typing import Annotated + +from fastapi import FastAPI, File, UploadFile + +app = FastAPI() + + +@app.post("/files/") +async def create_file(file: Annotated[bytes, File(description="A file read as bytes")]): + return {"file_size": len(file)} + + +@app.post("/uploadfile/") +async def create_upload_file( + file: Annotated[UploadFile, File(description="A file read as UploadFile")], +): + return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001_03_py310.py b/docs_src/request_files/tutorial001_03_py310.py new file mode 100644 index 000000000..d8005cc7d --- /dev/null +++ b/docs_src/request_files/tutorial001_03_py310.py @@ -0,0 +1,15 @@ +from fastapi import FastAPI, File, UploadFile + +app = FastAPI() + + +@app.post("/files/") +async def create_file(file: bytes = File(description="A file read as bytes")): + return {"file_size": len(file)} + + +@app.post("/uploadfile/") +async def create_upload_file( + file: UploadFile = File(description="A file read as UploadFile"), +): + return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001_an_py310.py b/docs_src/request_files/tutorial001_an_py310.py new file mode 100644 index 000000000..26a767221 --- /dev/null +++ b/docs_src/request_files/tutorial001_an_py310.py @@ -0,0 +1,15 @@ +from typing import Annotated + +from fastapi import FastAPI, File, UploadFile + +app = FastAPI() + + +@app.post("/files/") +async def create_file(file: Annotated[bytes, File()]): + return {"file_size": len(file)} + + +@app.post("/uploadfile/") +async def create_upload_file(file: UploadFile): + return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001_py310.py b/docs_src/request_files/tutorial001_py310.py new file mode 100644 index 000000000..2e0ea6391 --- /dev/null +++ b/docs_src/request_files/tutorial001_py310.py @@ -0,0 +1,13 @@ +from fastapi import FastAPI, File, UploadFile + +app = FastAPI() + + +@app.post("/files/") +async def create_file(file: bytes = File()): + return {"file_size": len(file)} + + +@app.post("/uploadfile/") +async def create_upload_file(file: UploadFile): + return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial002_an_py310.py b/docs_src/request_files/tutorial002_an_py310.py new file mode 100644 index 000000000..db524ceab --- /dev/null +++ b/docs_src/request_files/tutorial002_an_py310.py @@ -0,0 +1,33 @@ +from typing import Annotated + +from fastapi import FastAPI, File, UploadFile +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +@app.post("/files/") +async def create_files(files: Annotated[list[bytes], File()]): + return {"file_sizes": [len(file) for file in files]} + + +@app.post("/uploadfiles/") +async def create_upload_files(files: list[UploadFile]): + return {"filenames": [file.filename for file in files]} + + +@app.get("/") +async def main(): + content = """ + +
+ + +
+
+ + +
+ + """ + return HTMLResponse(content=content) diff --git a/docs_src/request_files/tutorial002_py310.py b/docs_src/request_files/tutorial002_py310.py new file mode 100644 index 000000000..b64cf5598 --- /dev/null +++ b/docs_src/request_files/tutorial002_py310.py @@ -0,0 +1,31 @@ +from fastapi import FastAPI, File, UploadFile +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +@app.post("/files/") +async def create_files(files: list[bytes] = File()): + return {"file_sizes": [len(file) for file in files]} + + +@app.post("/uploadfiles/") +async def create_upload_files(files: list[UploadFile]): + return {"filenames": [file.filename for file in files]} + + +@app.get("/") +async def main(): + content = """ + +
+ + +
+
+ + +
+ + """ + return HTMLResponse(content=content) diff --git a/docs_src/request_files/tutorial003_an_py310.py b/docs_src/request_files/tutorial003_an_py310.py new file mode 100644 index 000000000..5a8c5dab5 --- /dev/null +++ b/docs_src/request_files/tutorial003_an_py310.py @@ -0,0 +1,39 @@ +from typing import Annotated + +from fastapi import FastAPI, File, UploadFile +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +@app.post("/files/") +async def create_files( + files: Annotated[list[bytes], File(description="Multiple files as bytes")], +): + return {"file_sizes": [len(file) for file in files]} + + +@app.post("/uploadfiles/") +async def create_upload_files( + files: Annotated[ + list[UploadFile], File(description="Multiple files as UploadFile") + ], +): + return {"filenames": [file.filename for file in files]} + + +@app.get("/") +async def main(): + content = """ + +
+ + +
+
+ + +
+ + """ + return HTMLResponse(content=content) diff --git a/docs_src/request_files/tutorial003_py310.py b/docs_src/request_files/tutorial003_py310.py new file mode 100644 index 000000000..96f5e8742 --- /dev/null +++ b/docs_src/request_files/tutorial003_py310.py @@ -0,0 +1,35 @@ +from fastapi import FastAPI, File, UploadFile +from fastapi.responses import HTMLResponse + +app = FastAPI() + + +@app.post("/files/") +async def create_files( + files: list[bytes] = File(description="Multiple files as bytes"), +): + return {"file_sizes": [len(file) for file in files]} + + +@app.post("/uploadfiles/") +async def create_upload_files( + files: list[UploadFile] = File(description="Multiple files as UploadFile"), +): + return {"filenames": [file.filename for file in files]} + + +@app.get("/") +async def main(): + content = """ + +
+ + +
+
+ + +
+ + """ + return HTMLResponse(content=content) diff --git a/docs_src/request_form_models/tutorial001_an_py310.py b/docs_src/request_form_models/tutorial001_an_py310.py new file mode 100644 index 000000000..7cc81aae9 --- /dev/null +++ b/docs_src/request_form_models/tutorial001_an_py310.py @@ -0,0 +1,16 @@ +from typing import Annotated + +from fastapi import FastAPI, Form +from pydantic import BaseModel + +app = FastAPI() + + +class FormData(BaseModel): + username: str + password: str + + +@app.post("/login/") +async def login(data: Annotated[FormData, Form()]): + return data diff --git a/docs_src/request_form_models/tutorial001_py310.py b/docs_src/request_form_models/tutorial001_py310.py new file mode 100644 index 000000000..98feff0b9 --- /dev/null +++ b/docs_src/request_form_models/tutorial001_py310.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI, Form +from pydantic import BaseModel + +app = FastAPI() + + +class FormData(BaseModel): + username: str + password: str + + +@app.post("/login/") +async def login(data: FormData = Form()): + return data diff --git a/docs_src/request_form_models/tutorial002_an_py310.py b/docs_src/request_form_models/tutorial002_an_py310.py new file mode 100644 index 000000000..3004e0852 --- /dev/null +++ b/docs_src/request_form_models/tutorial002_an_py310.py @@ -0,0 +1,17 @@ +from typing import Annotated + +from fastapi import FastAPI, Form +from pydantic import BaseModel + +app = FastAPI() + + +class FormData(BaseModel): + username: str + password: str + model_config = {"extra": "forbid"} + + +@app.post("/login/") +async def login(data: Annotated[FormData, Form()]): + return data diff --git a/docs_src/request_form_models/tutorial002_py310.py b/docs_src/request_form_models/tutorial002_py310.py new file mode 100644 index 000000000..59b329e8d --- /dev/null +++ b/docs_src/request_form_models/tutorial002_py310.py @@ -0,0 +1,15 @@ +from fastapi import FastAPI, Form +from pydantic import BaseModel + +app = FastAPI() + + +class FormData(BaseModel): + username: str + password: str + model_config = {"extra": "forbid"} + + +@app.post("/login/") +async def login(data: FormData = Form()): + return data diff --git a/docs_src/request_forms/tutorial001_an_py310.py b/docs_src/request_forms/tutorial001_an_py310.py new file mode 100644 index 000000000..8e9d2ea53 --- /dev/null +++ b/docs_src/request_forms/tutorial001_an_py310.py @@ -0,0 +1,10 @@ +from typing import Annotated + +from fastapi import FastAPI, Form + +app = FastAPI() + + +@app.post("/login/") +async def login(username: Annotated[str, Form()], password: Annotated[str, Form()]): + return {"username": username} diff --git a/docs_src/request_forms/tutorial001_py310.py b/docs_src/request_forms/tutorial001_py310.py new file mode 100644 index 000000000..a53770001 --- /dev/null +++ b/docs_src/request_forms/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI, Form + +app = FastAPI() + + +@app.post("/login/") +async def login(username: str = Form(), password: str = Form()): + return {"username": username} diff --git a/docs_src/request_forms_and_files/tutorial001_an_py310.py b/docs_src/request_forms_and_files/tutorial001_an_py310.py new file mode 100644 index 000000000..12cc43e50 --- /dev/null +++ b/docs_src/request_forms_and_files/tutorial001_an_py310.py @@ -0,0 +1,18 @@ +from typing import Annotated + +from fastapi import FastAPI, File, Form, UploadFile + +app = FastAPI() + + +@app.post("/files/") +async def create_file( + file: Annotated[bytes, File()], + fileb: Annotated[UploadFile, File()], + token: Annotated[str, Form()], +): + return { + "file_size": len(file), + "token": token, + "fileb_content_type": fileb.content_type, + } diff --git a/docs_src/request_forms_and_files/tutorial001_py310.py b/docs_src/request_forms_and_files/tutorial001_py310.py new file mode 100644 index 000000000..7b5224ce5 --- /dev/null +++ b/docs_src/request_forms_and_files/tutorial001_py310.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI, File, Form, UploadFile + +app = FastAPI() + + +@app.post("/files/") +async def create_file( + file: bytes = File(), fileb: UploadFile = File(), token: str = Form() +): + return { + "file_size": len(file), + "token": token, + "fileb_content_type": fileb.content_type, + } diff --git a/docs_src/response_change_status_code/tutorial001_py310.py b/docs_src/response_change_status_code/tutorial001_py310.py new file mode 100644 index 000000000..197decbfb --- /dev/null +++ b/docs_src/response_change_status_code/tutorial001_py310.py @@ -0,0 +1,13 @@ +from fastapi import FastAPI, Response, status + +app = FastAPI() + +tasks = {"foo": "Listen to the Bar Fighters"} + + +@app.put("/get-or-create-task/{task_id}", status_code=200) +def get_or_create_task(task_id: str, response: Response): + if task_id not in tasks: + tasks[task_id] = "This didn't exist before" + response.status_code = status.HTTP_201_CREATED + return tasks[task_id] diff --git a/docs_src/response_cookies/tutorial001_py310.py b/docs_src/response_cookies/tutorial001_py310.py new file mode 100644 index 000000000..33f8e8f6e --- /dev/null +++ b/docs_src/response_cookies/tutorial001_py310.py @@ -0,0 +1,12 @@ +from fastapi import FastAPI +from fastapi.responses import JSONResponse + +app = FastAPI() + + +@app.post("/cookie/") +def create_cookie(): + content = {"message": "Come to the dark side, we have cookies"} + response = JSONResponse(content=content) + response.set_cookie(key="fakesession", value="fake-cookie-session-value") + return response diff --git a/docs_src/response_cookies/tutorial002_py310.py b/docs_src/response_cookies/tutorial002_py310.py new file mode 100644 index 000000000..76c06fdb9 --- /dev/null +++ b/docs_src/response_cookies/tutorial002_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI, Response + +app = FastAPI() + + +@app.post("/cookie-and-object/") +def create_cookie(response: Response): + response.set_cookie(key="fakesession", value="fake-cookie-session-value") + return {"message": "Come to the dark side, we have cookies"} diff --git a/docs_src/response_directly/tutorial001_py39.py b/docs_src/response_directly/tutorial001_py39.py deleted file mode 100644 index 5ab655a8a..000000000 --- a/docs_src/response_directly/tutorial001_py39.py +++ /dev/null @@ -1,22 +0,0 @@ -from datetime import datetime -from typing import Union - -from fastapi import FastAPI -from fastapi.encoders import jsonable_encoder -from fastapi.responses import JSONResponse -from pydantic import BaseModel - - -class Item(BaseModel): - title: str - timestamp: datetime - description: Union[str, None] = None - - -app = FastAPI() - - -@app.put("/items/{id}") -def update_item(id: str, item: Item): - json_compatible_item_data = jsonable_encoder(item) - return JSONResponse(content=json_compatible_item_data) diff --git a/docs_src/response_directly/tutorial002_py310.py b/docs_src/response_directly/tutorial002_py310.py new file mode 100644 index 000000000..6643da6e6 --- /dev/null +++ b/docs_src/response_directly/tutorial002_py310.py @@ -0,0 +1,18 @@ +from fastapi import FastAPI, Response + +app = FastAPI() + + +@app.get("/legacy/") +def get_legacy_data(): + data = """ + +
+ Apply shampoo here. +
+ + You'll have to use soap here. + +
+ """ + return Response(content=data, media_type="application/xml") diff --git a/docs_src/response_headers/tutorial001_py310.py b/docs_src/response_headers/tutorial001_py310.py new file mode 100644 index 000000000..2da02a470 --- /dev/null +++ b/docs_src/response_headers/tutorial001_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI +from fastapi.responses import JSONResponse + +app = FastAPI() + + +@app.get("/headers/") +def get_headers(): + content = {"message": "Hello World"} + headers = {"X-Cat-Dog": "alone in the world", "Content-Language": "en-US"} + return JSONResponse(content=content, headers=headers) diff --git a/docs_src/response_headers/tutorial002_py310.py b/docs_src/response_headers/tutorial002_py310.py new file mode 100644 index 000000000..d2c498305 --- /dev/null +++ b/docs_src/response_headers/tutorial002_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI, Response + +app = FastAPI() + + +@app.get("/headers-and-object/") +def get_headers(response: Response): + response.headers["X-Cat-Dog"] = "alone in the world" + return {"message": "Hello World"} diff --git a/docs_src/response_model/tutorial001_01_py39.py b/docs_src/response_model/tutorial001_01_py39.py deleted file mode 100644 index 16c78aa3f..000000000 --- a/docs_src/response_model/tutorial001_01_py39.py +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: list[str] = [] - - -@app.post("/items/") -async def create_item(item: Item) -> Item: - return item - - -@app.get("/items/") -async def read_items() -> list[Item]: - return [ - Item(name="Portal Gun", price=42.0), - Item(name="Plumbus", price=32.0), - ] diff --git a/docs_src/response_model/tutorial001_py39.py b/docs_src/response_model/tutorial001_py39.py deleted file mode 100644 index 261e252d0..000000000 --- a/docs_src/response_model/tutorial001_py39.py +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Any, Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: list[str] = [] - - -@app.post("/items/", response_model=Item) -async def create_item(item: Item) -> Any: - return item - - -@app.get("/items/", response_model=list[Item]) -async def read_items() -> Any: - return [ - {"name": "Portal Gun", "price": 42.0}, - {"name": "Plumbus", "price": 32.0}, - ] diff --git a/docs_src/response_model/tutorial002_py39.py b/docs_src/response_model/tutorial002_py39.py deleted file mode 100644 index a58668f9e..000000000 --- a/docs_src/response_model/tutorial002_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, EmailStr - -app = FastAPI() - - -class UserIn(BaseModel): - username: str - password: str - email: EmailStr - full_name: Union[str, None] = None - - -# Don't do this in production! -@app.post("/user/") -async def create_user(user: UserIn) -> UserIn: - return user diff --git a/docs_src/response_model/tutorial003_01_py39.py b/docs_src/response_model/tutorial003_01_py39.py deleted file mode 100644 index 52694b551..000000000 --- a/docs_src/response_model/tutorial003_01_py39.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, EmailStr - -app = FastAPI() - - -class BaseUser(BaseModel): - username: str - email: EmailStr - full_name: Union[str, None] = None - - -class UserIn(BaseUser): - password: str - - -@app.post("/user/") -async def create_user(user: UserIn) -> BaseUser: - return user diff --git a/docs_src/response_model/tutorial003_02_py310.py b/docs_src/response_model/tutorial003_02_py310.py new file mode 100644 index 000000000..df6a09646 --- /dev/null +++ b/docs_src/response_model/tutorial003_02_py310.py @@ -0,0 +1,11 @@ +from fastapi import FastAPI, Response +from fastapi.responses import JSONResponse, RedirectResponse + +app = FastAPI() + + +@app.get("/portal") +async def get_portal(teleport: bool = False) -> Response: + if teleport: + return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ") + return JSONResponse(content={"message": "Here's your interdimensional portal."}) diff --git a/docs_src/response_model/tutorial003_03_py310.py b/docs_src/response_model/tutorial003_03_py310.py new file mode 100644 index 000000000..0d4bd8de5 --- /dev/null +++ b/docs_src/response_model/tutorial003_03_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI +from fastapi.responses import RedirectResponse + +app = FastAPI() + + +@app.get("/teleport") +async def get_teleport() -> RedirectResponse: + return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ") diff --git a/docs_src/response_model/tutorial003_04_py39.py b/docs_src/response_model/tutorial003_04_py39.py deleted file mode 100644 index b13a92692..000000000 --- a/docs_src/response_model/tutorial003_04_py39.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Response -from fastapi.responses import RedirectResponse - -app = FastAPI() - - -@app.get("/portal") -async def get_portal(teleport: bool = False) -> Union[Response, dict]: - if teleport: - return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ") - return {"message": "Here's your interdimensional portal."} diff --git a/docs_src/response_model/tutorial003_05_py39.py b/docs_src/response_model/tutorial003_05_py39.py deleted file mode 100644 index 0962061a6..000000000 --- a/docs_src/response_model/tutorial003_05_py39.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Response -from fastapi.responses import RedirectResponse - -app = FastAPI() - - -@app.get("/portal", response_model=None) -async def get_portal(teleport: bool = False) -> Union[Response, dict]: - if teleport: - return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ") - return {"message": "Here's your interdimensional portal."} diff --git a/docs_src/response_model/tutorial003_py39.py b/docs_src/response_model/tutorial003_py39.py deleted file mode 100644 index c42dbc707..000000000 --- a/docs_src/response_model/tutorial003_py39.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Any, Union - -from fastapi import FastAPI -from pydantic import BaseModel, EmailStr - -app = FastAPI() - - -class UserIn(BaseModel): - username: str - password: str - email: EmailStr - full_name: Union[str, None] = None - - -class UserOut(BaseModel): - username: str - email: EmailStr - full_name: Union[str, None] = None - - -@app.post("/user/", response_model=UserOut) -async def create_user(user: UserIn) -> Any: - return user diff --git a/docs_src/response_model/tutorial004_py39.py b/docs_src/response_model/tutorial004_py39.py deleted file mode 100644 index 9463b45ec..000000000 --- a/docs_src/response_model/tutorial004_py39.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: float = 10.5 - tags: list[str] = [] - - -items = { - "foo": {"name": "Foo", "price": 50.2}, - "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2}, - "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []}, -} - - -@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True) -async def read_item(item_id: str): - return items[item_id] diff --git a/docs_src/response_model/tutorial005_py39.py b/docs_src/response_model/tutorial005_py39.py deleted file mode 100644 index 30eb9f8e3..000000000 --- a/docs_src/response_model/tutorial005_py39.py +++ /dev/null @@ -1,39 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: float = 10.5 - - -items = { - "foo": {"name": "Foo", "price": 50.2}, - "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2}, - "baz": { - "name": "Baz", - "description": "There goes my baz", - "price": 50.2, - "tax": 10.5, - }, -} - - -@app.get( - "/items/{item_id}/name", - response_model=Item, - response_model_include={"name", "description"}, -) -async def read_item_name(item_id: str): - return items[item_id] - - -@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"}) -async def read_item_public_data(item_id: str): - return items[item_id] diff --git a/docs_src/response_model/tutorial006_py39.py b/docs_src/response_model/tutorial006_py39.py deleted file mode 100644 index 3ffdb512b..000000000 --- a/docs_src/response_model/tutorial006_py39.py +++ /dev/null @@ -1,39 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: float = 10.5 - - -items = { - "foo": {"name": "Foo", "price": 50.2}, - "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2}, - "baz": { - "name": "Baz", - "description": "There goes my baz", - "price": 50.2, - "tax": 10.5, - }, -} - - -@app.get( - "/items/{item_id}/name", - response_model=Item, - response_model_include=["name", "description"], -) -async def read_item_name(item_id: str): - return items[item_id] - - -@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude=["tax"]) -async def read_item_public_data(item_id: str): - return items[item_id] diff --git a/docs_src/response_status_code/tutorial001_py310.py b/docs_src/response_status_code/tutorial001_py310.py new file mode 100644 index 000000000..14b6d6e67 --- /dev/null +++ b/docs_src/response_status_code/tutorial001_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.post("/items/", status_code=201) +async def create_item(name: str): + return {"name": name} diff --git a/docs_src/response_status_code/tutorial002_py310.py b/docs_src/response_status_code/tutorial002_py310.py new file mode 100644 index 000000000..4fcc9829d --- /dev/null +++ b/docs_src/response_status_code/tutorial002_py310.py @@ -0,0 +1,8 @@ +from fastapi import FastAPI, status + +app = FastAPI() + + +@app.post("/items/", status_code=status.HTTP_201_CREATED) +async def create_item(name: str): + return {"name": name} diff --git a/docs_src/schema_extra_example/tutorial001_pv1_py310.py b/docs_src/schema_extra_example/tutorial001_pv1_py310.py deleted file mode 100644 index b13b8a8c2..000000000 --- a/docs_src/schema_extra_example/tutorial001_pv1_py310.py +++ /dev/null @@ -1,29 +0,0 @@ -from fastapi import FastAPI -from pydantic.v1 import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: str | None = None - price: float - tax: float | None = None - - class Config: - schema_extra = { - "examples": [ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - } - ] - } - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial001_pv1_py39.py b/docs_src/schema_extra_example/tutorial001_pv1_py39.py deleted file mode 100644 index 3240b35d6..000000000 --- a/docs_src/schema_extra_example/tutorial001_pv1_py39.py +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic.v1 import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - class Config: - schema_extra = { - "examples": [ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - } - ] - } - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial001_py39.py b/docs_src/schema_extra_example/tutorial001_py39.py deleted file mode 100644 index 32a66db3a..000000000 --- a/docs_src/schema_extra_example/tutorial001_py39.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - model_config = { - "json_schema_extra": { - "examples": [ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - } - ] - } - } - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial002_py39.py b/docs_src/schema_extra_example/tutorial002_py39.py deleted file mode 100644 index 70f06567c..000000000 --- a/docs_src/schema_extra_example/tutorial002_py39.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from pydantic import BaseModel, Field - -app = FastAPI() - - -class Item(BaseModel): - name: str = Field(examples=["Foo"]) - description: Union[str, None] = Field(default=None, examples=["A very nice Item"]) - price: float = Field(examples=[35.4]) - tax: Union[float, None] = Field(default=None, examples=[3.2]) - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial003_an_py39.py b/docs_src/schema_extra_example/tutorial003_an_py39.py deleted file mode 100644 index 472808561..000000000 --- a/docs_src/schema_extra_example/tutorial003_an_py39.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - item_id: int, - item: Annotated[ - Item, - Body( - examples=[ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - } - ], - ), - ], -): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial003_py39.py b/docs_src/schema_extra_example/tutorial003_py39.py deleted file mode 100644 index 385f3de8a..000000000 --- a/docs_src/schema_extra_example/tutorial003_py39.py +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - item_id: int, - item: Item = Body( - examples=[ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - } - ], - ), -): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial004_an_py39.py b/docs_src/schema_extra_example/tutorial004_an_py39.py deleted file mode 100644 index dc5a8fe49..000000000 --- a/docs_src/schema_extra_example/tutorial004_an_py39.py +++ /dev/null @@ -1,43 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int, - item: Annotated[ - Item, - Body( - examples=[ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, - { - "name": "Bar", - "price": "35.4", - }, - { - "name": "Baz", - "price": "thirty five point four", - }, - ], - ), - ], -): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial004_py39.py b/docs_src/schema_extra_example/tutorial004_py39.py deleted file mode 100644 index 75514a3e9..000000000 --- a/docs_src/schema_extra_example/tutorial004_py39.py +++ /dev/null @@ -1,40 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int, - item: Item = Body( - examples=[ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, - { - "name": "Bar", - "price": "35.4", - }, - { - "name": "Baz", - "price": "thirty five point four", - }, - ], - ), -): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial005_an_py39.py b/docs_src/schema_extra_example/tutorial005_an_py39.py deleted file mode 100644 index edeb1affc..000000000 --- a/docs_src/schema_extra_example/tutorial005_an_py39.py +++ /dev/null @@ -1,54 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int, - item: Annotated[ - Item, - Body( - openapi_examples={ - "normal": { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, - }, - "converted": { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": { - "name": "Bar", - "price": "35.4", - }, - }, - "invalid": { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", - }, - }, - }, - ), - ], -): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial005_py39.py b/docs_src/schema_extra_example/tutorial005_py39.py deleted file mode 100644 index b8217c27e..000000000 --- a/docs_src/schema_extra_example/tutorial005_py39.py +++ /dev/null @@ -1,51 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int, - item: Item = Body( - openapi_examples={ - "normal": { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, - }, - "converted": { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": { - "name": "Bar", - "price": "35.4", - }, - }, - "invalid": { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", - }, - }, - }, - ), -): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/security/tutorial001_an_py310.py b/docs_src/security/tutorial001_an_py310.py new file mode 100644 index 000000000..de110402e --- /dev/null +++ b/docs_src/security/tutorial001_an_py310.py @@ -0,0 +1,13 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI +from fastapi.security import OAuth2PasswordBearer + +app = FastAPI() + +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") + + +@app.get("/items/") +async def read_items(token: Annotated[str, Depends(oauth2_scheme)]): + return {"token": token} diff --git a/docs_src/security/tutorial001_py310.py b/docs_src/security/tutorial001_py310.py new file mode 100644 index 000000000..224e59602 --- /dev/null +++ b/docs_src/security/tutorial001_py310.py @@ -0,0 +1,11 @@ +from fastapi import Depends, FastAPI +from fastapi.security import OAuth2PasswordBearer + +app = FastAPI() + +oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") + + +@app.get("/items/") +async def read_items(token: str = Depends(oauth2_scheme)): + return {"token": token} diff --git a/docs_src/security/tutorial002_an_py39.py b/docs_src/security/tutorial002_an_py39.py deleted file mode 100644 index 7ff1c470b..000000000 --- a/docs_src/security/tutorial002_an_py39.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI -from fastapi.security import OAuth2PasswordBearer -from pydantic import BaseModel - -app = FastAPI() - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -def fake_decode_token(token): - return User( - username=token + "fakedecoded", email="john@example.com", full_name="John Doe" - ) - - -async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): - user = fake_decode_token(token) - return user - - -@app.get("/users/me") -async def read_users_me(current_user: Annotated[User, Depends(get_current_user)]): - return current_user diff --git a/docs_src/security/tutorial002_py39.py b/docs_src/security/tutorial002_py39.py deleted file mode 100644 index bfd035221..000000000 --- a/docs_src/security/tutorial002_py39.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI -from fastapi.security import OAuth2PasswordBearer -from pydantic import BaseModel - -app = FastAPI() - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -def fake_decode_token(token): - return User( - username=token + "fakedecoded", email="john@example.com", full_name="John Doe" - ) - - -async def get_current_user(token: str = Depends(oauth2_scheme)): - user = fake_decode_token(token) - return user - - -@app.get("/users/me") -async def read_users_me(current_user: User = Depends(get_current_user)): - return current_user diff --git a/docs_src/security/tutorial003_an_py39.py b/docs_src/security/tutorial003_an_py39.py deleted file mode 100644 index b396210c8..000000000 --- a/docs_src/security/tutorial003_an_py39.py +++ /dev/null @@ -1,94 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI, HTTPException, status -from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from pydantic import BaseModel - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "fakehashedsecret", - "disabled": False, - }, - "alice": { - "username": "alice", - "full_name": "Alice Wonderson", - "email": "alice@example.com", - "hashed_password": "fakehashedsecret2", - "disabled": True, - }, -} - -app = FastAPI() - - -def fake_hash_password(password: str): - return "fakehashed" + password - - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def fake_decode_token(token): - # This doesn't provide any security at all - # Check the next version - user = get_user(fake_users_db, token) - return user - - -async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): - user = fake_decode_token(token) - if not user: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Not authenticated", - headers={"WWW-Authenticate": "Bearer"}, - ) - return user - - -async def get_current_active_user( - current_user: Annotated[User, Depends(get_current_user)], -): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]): - user_dict = fake_users_db.get(form_data.username) - if not user_dict: - raise HTTPException(status_code=400, detail="Incorrect username or password") - user = UserInDB(**user_dict) - hashed_password = fake_hash_password(form_data.password) - if not hashed_password == user.hashed_password: - raise HTTPException(status_code=400, detail="Incorrect username or password") - - return {"access_token": user.username, "token_type": "bearer"} - - -@app.get("/users/me") -async def read_users_me( - current_user: Annotated[User, Depends(get_current_active_user)], -): - return current_user diff --git a/docs_src/security/tutorial003_py39.py b/docs_src/security/tutorial003_py39.py deleted file mode 100644 index ce7a71b68..000000000 --- a/docs_src/security/tutorial003_py39.py +++ /dev/null @@ -1,90 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI, HTTPException, status -from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from pydantic import BaseModel - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "fakehashedsecret", - "disabled": False, - }, - "alice": { - "username": "alice", - "full_name": "Alice Wonderson", - "email": "alice@example.com", - "hashed_password": "fakehashedsecret2", - "disabled": True, - }, -} - -app = FastAPI() - - -def fake_hash_password(password: str): - return "fakehashed" + password - - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def fake_decode_token(token): - # This doesn't provide any security at all - # Check the next version - user = get_user(fake_users_db, token) - return user - - -async def get_current_user(token: str = Depends(oauth2_scheme)): - user = fake_decode_token(token) - if not user: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Not authenticated", - headers={"WWW-Authenticate": "Bearer"}, - ) - return user - - -async def get_current_active_user(current_user: User = Depends(get_current_user)): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login(form_data: OAuth2PasswordRequestForm = Depends()): - user_dict = fake_users_db.get(form_data.username) - if not user_dict: - raise HTTPException(status_code=400, detail="Incorrect username or password") - user = UserInDB(**user_dict) - hashed_password = fake_hash_password(form_data.password) - if not hashed_password == user.hashed_password: - raise HTTPException(status_code=400, detail="Incorrect username or password") - - return {"access_token": user.username, "token_type": "bearer"} - - -@app.get("/users/me") -async def read_users_me(current_user: User = Depends(get_current_active_user)): - return current_user diff --git a/docs_src/security/tutorial004_an_py39.py b/docs_src/security/tutorial004_an_py39.py deleted file mode 100644 index 73b3d456d..000000000 --- a/docs_src/security/tutorial004_an_py39.py +++ /dev/null @@ -1,147 +0,0 @@ -from datetime import datetime, timedelta, timezone -from typing import Annotated, Union - -import jwt -from fastapi import Depends, FastAPI, HTTPException, status -from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from jwt.exceptions import InvalidTokenError -from pwdlib import PasswordHash -from pydantic import BaseModel - -# to get a string like this run: -# openssl rand -hex 32 -SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" -ALGORITHM = "HS256" -ACCESS_TOKEN_EXPIRE_MINUTES = 30 - - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", - "disabled": False, - } -} - - -class Token(BaseModel): - access_token: str - token_type: str - - -class TokenData(BaseModel): - username: Union[str, None] = None - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -password_hash = PasswordHash.recommended() - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - -app = FastAPI() - - -def verify_password(plain_password, hashed_password): - return password_hash.verify(plain_password, hashed_password) - - -def get_password_hash(password): - return password_hash.hash(password) - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def authenticate_user(fake_db, username: str, password: str): - user = get_user(fake_db, username) - if not user: - return False - if not verify_password(password, user.hashed_password): - return False - return user - - -def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): - to_encode = data.copy() - if expires_delta: - expire = datetime.now(timezone.utc) + expires_delta - else: - expire = datetime.now(timezone.utc) + timedelta(minutes=15) - to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) - return encoded_jwt - - -async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": "Bearer"}, - ) - try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - username = payload.get("sub") - if username is None: - raise credentials_exception - token_data = TokenData(username=username) - except InvalidTokenError: - raise credentials_exception - user = get_user(fake_users_db, username=token_data.username) - if user is None: - raise credentials_exception - return user - - -async def get_current_active_user( - current_user: Annotated[User, Depends(get_current_user)], -): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login_for_access_token( - form_data: Annotated[OAuth2PasswordRequestForm, Depends()], -) -> Token: - user = authenticate_user(fake_users_db, form_data.username, form_data.password) - if not user: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect username or password", - headers={"WWW-Authenticate": "Bearer"}, - ) - access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) - access_token = create_access_token( - data={"sub": user.username}, expires_delta=access_token_expires - ) - return Token(access_token=access_token, token_type="bearer") - - -@app.get("/users/me/") -async def read_users_me( - current_user: Annotated[User, Depends(get_current_active_user)], -) -> User: - return current_user - - -@app.get("/users/me/items/") -async def read_own_items( - current_user: Annotated[User, Depends(get_current_active_user)], -): - return [{"item_id": "Foo", "owner": current_user.username}] diff --git a/docs_src/security/tutorial004_py39.py b/docs_src/security/tutorial004_py39.py deleted file mode 100644 index e67403d5d..000000000 --- a/docs_src/security/tutorial004_py39.py +++ /dev/null @@ -1,141 +0,0 @@ -from datetime import datetime, timedelta, timezone -from typing import Union - -import jwt -from fastapi import Depends, FastAPI, HTTPException, status -from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from jwt.exceptions import InvalidTokenError -from pwdlib import PasswordHash -from pydantic import BaseModel - -# to get a string like this run: -# openssl rand -hex 32 -SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" -ALGORITHM = "HS256" -ACCESS_TOKEN_EXPIRE_MINUTES = 30 - - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", - "disabled": False, - } -} - - -class Token(BaseModel): - access_token: str - token_type: str - - -class TokenData(BaseModel): - username: Union[str, None] = None - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -password_hash = PasswordHash.recommended() - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - -app = FastAPI() - - -def verify_password(plain_password, hashed_password): - return password_hash.verify(plain_password, hashed_password) - - -def get_password_hash(password): - return password_hash.hash(password) - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def authenticate_user(fake_db, username: str, password: str): - user = get_user(fake_db, username) - if not user: - return False - if not verify_password(password, user.hashed_password): - return False - return user - - -def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): - to_encode = data.copy() - if expires_delta: - expire = datetime.now(timezone.utc) + expires_delta - else: - expire = datetime.now(timezone.utc) + timedelta(minutes=15) - to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) - return encoded_jwt - - -async def get_current_user(token: str = Depends(oauth2_scheme)): - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": "Bearer"}, - ) - try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - username = payload.get("sub") - if username is None: - raise credentials_exception - token_data = TokenData(username=username) - except InvalidTokenError: - raise credentials_exception - user = get_user(fake_users_db, username=token_data.username) - if user is None: - raise credentials_exception - return user - - -async def get_current_active_user(current_user: User = Depends(get_current_user)): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login_for_access_token( - form_data: OAuth2PasswordRequestForm = Depends(), -) -> Token: - user = authenticate_user(fake_users_db, form_data.username, form_data.password) - if not user: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect username or password", - headers={"WWW-Authenticate": "Bearer"}, - ) - access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) - access_token = create_access_token( - data={"sub": user.username}, expires_delta=access_token_expires - ) - return Token(access_token=access_token, token_type="bearer") - - -@app.get("/users/me/") -async def read_users_me(current_user: User = Depends(get_current_active_user)) -> User: - return current_user - - -@app.get("/users/me/items/") -async def read_own_items(current_user: User = Depends(get_current_active_user)): - return [{"item_id": "Foo", "owner": current_user.username}] diff --git a/docs_src/security/tutorial005_an_py39.py b/docs_src/security/tutorial005_an_py39.py deleted file mode 100644 index 1aeba688a..000000000 --- a/docs_src/security/tutorial005_an_py39.py +++ /dev/null @@ -1,179 +0,0 @@ -from datetime import datetime, timedelta, timezone -from typing import Annotated, Union - -import jwt -from fastapi import Depends, FastAPI, HTTPException, Security, status -from fastapi.security import ( - OAuth2PasswordBearer, - OAuth2PasswordRequestForm, - SecurityScopes, -) -from jwt.exceptions import InvalidTokenError -from pwdlib import PasswordHash -from pydantic import BaseModel, ValidationError - -# to get a string like this run: -# openssl rand -hex 32 -SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" -ALGORITHM = "HS256" -ACCESS_TOKEN_EXPIRE_MINUTES = 30 - - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", - "disabled": False, - }, - "alice": { - "username": "alice", - "full_name": "Alice Chains", - "email": "alicechains@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", - "disabled": True, - }, -} - - -class Token(BaseModel): - access_token: str - token_type: str - - -class TokenData(BaseModel): - username: Union[str, None] = None - scopes: list[str] = [] - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -password_hash = PasswordHash.recommended() - -oauth2_scheme = OAuth2PasswordBearer( - tokenUrl="token", - scopes={"me": "Read information about the current user.", "items": "Read items."}, -) - -app = FastAPI() - - -def verify_password(plain_password, hashed_password): - return password_hash.verify(plain_password, hashed_password) - - -def get_password_hash(password): - return password_hash.hash(password) - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def authenticate_user(fake_db, username: str, password: str): - user = get_user(fake_db, username) - if not user: - return False - if not verify_password(password, user.hashed_password): - return False - return user - - -def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): - to_encode = data.copy() - if expires_delta: - expire = datetime.now(timezone.utc) + expires_delta - else: - expire = datetime.now(timezone.utc) + timedelta(minutes=15) - to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) - return encoded_jwt - - -async def get_current_user( - security_scopes: SecurityScopes, token: Annotated[str, Depends(oauth2_scheme)] -): - if security_scopes.scopes: - authenticate_value = f'Bearer scope="{security_scopes.scope_str}"' - else: - authenticate_value = "Bearer" - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": authenticate_value}, - ) - try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - username = payload.get("sub") - if username is None: - raise credentials_exception - scope: str = payload.get("scope", "") - token_scopes = scope.split(" ") - token_data = TokenData(scopes=token_scopes, username=username) - except (InvalidTokenError, ValidationError): - raise credentials_exception - user = get_user(fake_users_db, username=token_data.username) - if user is None: - raise credentials_exception - for scope in security_scopes.scopes: - if scope not in token_data.scopes: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Not enough permissions", - headers={"WWW-Authenticate": authenticate_value}, - ) - return user - - -async def get_current_active_user( - current_user: Annotated[User, Security(get_current_user, scopes=["me"])], -): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login_for_access_token( - form_data: Annotated[OAuth2PasswordRequestForm, Depends()], -) -> Token: - user = authenticate_user(fake_users_db, form_data.username, form_data.password) - if not user: - raise HTTPException(status_code=400, detail="Incorrect username or password") - access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) - access_token = create_access_token( - data={"sub": user.username, "scope": " ".join(form_data.scopes)}, - expires_delta=access_token_expires, - ) - return Token(access_token=access_token, token_type="bearer") - - -@app.get("/users/me/") -async def read_users_me( - current_user: Annotated[User, Depends(get_current_active_user)], -) -> User: - return current_user - - -@app.get("/users/me/items/") -async def read_own_items( - current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])], -): - return [{"item_id": "Foo", "owner": current_user.username}] - - -@app.get("/status/") -async def read_system_status(current_user: Annotated[User, Depends(get_current_user)]): - return {"status": "ok"} diff --git a/docs_src/security/tutorial005_py39.py b/docs_src/security/tutorial005_py39.py deleted file mode 100644 index 32280aa48..000000000 --- a/docs_src/security/tutorial005_py39.py +++ /dev/null @@ -1,177 +0,0 @@ -from datetime import datetime, timedelta, timezone -from typing import Union - -import jwt -from fastapi import Depends, FastAPI, HTTPException, Security, status -from fastapi.security import ( - OAuth2PasswordBearer, - OAuth2PasswordRequestForm, - SecurityScopes, -) -from jwt.exceptions import InvalidTokenError -from pwdlib import PasswordHash -from pydantic import BaseModel, ValidationError - -# to get a string like this run: -# openssl rand -hex 32 -SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" -ALGORITHM = "HS256" -ACCESS_TOKEN_EXPIRE_MINUTES = 30 - - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", - "disabled": False, - }, - "alice": { - "username": "alice", - "full_name": "Alice Chains", - "email": "alicechains@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", - "disabled": True, - }, -} - - -class Token(BaseModel): - access_token: str - token_type: str - - -class TokenData(BaseModel): - username: Union[str, None] = None - scopes: list[str] = [] - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -password_hash = PasswordHash.recommended() - -oauth2_scheme = OAuth2PasswordBearer( - tokenUrl="token", - scopes={"me": "Read information about the current user.", "items": "Read items."}, -) - -app = FastAPI() - - -def verify_password(plain_password, hashed_password): - return password_hash.verify(plain_password, hashed_password) - - -def get_password_hash(password): - return password_hash.hash(password) - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def authenticate_user(fake_db, username: str, password: str): - user = get_user(fake_db, username) - if not user: - return False - if not verify_password(password, user.hashed_password): - return False - return user - - -def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): - to_encode = data.copy() - if expires_delta: - expire = datetime.now(timezone.utc) + expires_delta - else: - expire = datetime.now(timezone.utc) + timedelta(minutes=15) - to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) - return encoded_jwt - - -async def get_current_user( - security_scopes: SecurityScopes, token: str = Depends(oauth2_scheme) -): - if security_scopes.scopes: - authenticate_value = f'Bearer scope="{security_scopes.scope_str}"' - else: - authenticate_value = "Bearer" - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": authenticate_value}, - ) - try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - username: str = payload.get("sub") - if username is None: - raise credentials_exception - scope: str = payload.get("scope", "") - token_scopes = scope.split(" ") - token_data = TokenData(scopes=token_scopes, username=username) - except (InvalidTokenError, ValidationError): - raise credentials_exception - user = get_user(fake_users_db, username=token_data.username) - if user is None: - raise credentials_exception - for scope in security_scopes.scopes: - if scope not in token_data.scopes: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Not enough permissions", - headers={"WWW-Authenticate": authenticate_value}, - ) - return user - - -async def get_current_active_user( - current_user: User = Security(get_current_user, scopes=["me"]), -): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login_for_access_token( - form_data: OAuth2PasswordRequestForm = Depends(), -) -> Token: - user = authenticate_user(fake_users_db, form_data.username, form_data.password) - if not user: - raise HTTPException(status_code=400, detail="Incorrect username or password") - access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) - access_token = create_access_token( - data={"sub": user.username, "scope": " ".join(form_data.scopes)}, - expires_delta=access_token_expires, - ) - return Token(access_token=access_token, token_type="bearer") - - -@app.get("/users/me/") -async def read_users_me(current_user: User = Depends(get_current_active_user)) -> User: - return current_user - - -@app.get("/users/me/items/") -async def read_own_items( - current_user: User = Security(get_current_active_user, scopes=["items"]), -): - return [{"item_id": "Foo", "owner": current_user.username}] - - -@app.get("/status/") -async def read_system_status(current_user: User = Depends(get_current_user)): - return {"status": "ok"} diff --git a/docs_src/security/tutorial006_an_py310.py b/docs_src/security/tutorial006_an_py310.py new file mode 100644 index 000000000..03c696a4b --- /dev/null +++ b/docs_src/security/tutorial006_an_py310.py @@ -0,0 +1,13 @@ +from typing import Annotated + +from fastapi import Depends, FastAPI +from fastapi.security import HTTPBasic, HTTPBasicCredentials + +app = FastAPI() + +security = HTTPBasic() + + +@app.get("/users/me") +def read_current_user(credentials: Annotated[HTTPBasicCredentials, Depends(security)]): + return {"username": credentials.username, "password": credentials.password} diff --git a/docs_src/security/tutorial006_py310.py b/docs_src/security/tutorial006_py310.py new file mode 100644 index 000000000..29121ffd6 --- /dev/null +++ b/docs_src/security/tutorial006_py310.py @@ -0,0 +1,11 @@ +from fastapi import Depends, FastAPI +from fastapi.security import HTTPBasic, HTTPBasicCredentials + +app = FastAPI() + +security = HTTPBasic() + + +@app.get("/users/me") +def read_current_user(credentials: HTTPBasicCredentials = Depends(security)): + return {"username": credentials.username, "password": credentials.password} diff --git a/docs_src/security/tutorial007_an_py310.py b/docs_src/security/tutorial007_an_py310.py new file mode 100644 index 000000000..87ef98657 --- /dev/null +++ b/docs_src/security/tutorial007_an_py310.py @@ -0,0 +1,36 @@ +import secrets +from typing import Annotated + +from fastapi import Depends, FastAPI, HTTPException, status +from fastapi.security import HTTPBasic, HTTPBasicCredentials + +app = FastAPI() + +security = HTTPBasic() + + +def get_current_username( + credentials: Annotated[HTTPBasicCredentials, Depends(security)], +): + current_username_bytes = credentials.username.encode("utf8") + correct_username_bytes = b"stanleyjobson" + is_correct_username = secrets.compare_digest( + current_username_bytes, correct_username_bytes + ) + current_password_bytes = credentials.password.encode("utf8") + correct_password_bytes = b"swordfish" + is_correct_password = secrets.compare_digest( + current_password_bytes, correct_password_bytes + ) + if not (is_correct_username and is_correct_password): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect username or password", + headers={"WWW-Authenticate": "Basic"}, + ) + return credentials.username + + +@app.get("/users/me") +def read_current_user(username: Annotated[str, Depends(get_current_username)]): + return {"username": username} diff --git a/docs_src/security/tutorial007_py310.py b/docs_src/security/tutorial007_py310.py new file mode 100644 index 000000000..ac816eb0c --- /dev/null +++ b/docs_src/security/tutorial007_py310.py @@ -0,0 +1,33 @@ +import secrets + +from fastapi import Depends, FastAPI, HTTPException, status +from fastapi.security import HTTPBasic, HTTPBasicCredentials + +app = FastAPI() + +security = HTTPBasic() + + +def get_current_username(credentials: HTTPBasicCredentials = Depends(security)): + current_username_bytes = credentials.username.encode("utf8") + correct_username_bytes = b"stanleyjobson" + is_correct_username = secrets.compare_digest( + current_username_bytes, correct_username_bytes + ) + current_password_bytes = credentials.password.encode("utf8") + correct_password_bytes = b"swordfish" + is_correct_password = secrets.compare_digest( + current_password_bytes, correct_password_bytes + ) + if not (is_correct_username and is_correct_password): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect username or password", + headers={"WWW-Authenticate": "Basic"}, + ) + return credentials.username + + +@app.get("/users/me") +def read_current_user(username: str = Depends(get_current_username)): + return {"username": username} diff --git a/docs_src/separate_openapi_schemas/tutorial001_py39.py b/docs_src/separate_openapi_schemas/tutorial001_py39.py deleted file mode 100644 index 63cffd1e3..000000000 --- a/docs_src/separate_openapi_schemas/tutorial001_py39.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import Optional - -from fastapi import FastAPI -from pydantic import BaseModel - - -class Item(BaseModel): - name: str - description: Optional[str] = None - - -app = FastAPI() - - -@app.post("/items/") -def create_item(item: Item): - return item - - -@app.get("/items/") -def read_items() -> list[Item]: - return [ - Item( - name="Portal Gun", - description="Device to travel through the multi-rick-verse", - ), - Item(name="Plumbus"), - ] diff --git a/docs_src/separate_openapi_schemas/tutorial002_py39.py b/docs_src/separate_openapi_schemas/tutorial002_py39.py deleted file mode 100644 index 50d997d92..000000000 --- a/docs_src/separate_openapi_schemas/tutorial002_py39.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import Optional - -from fastapi import FastAPI -from pydantic import BaseModel - - -class Item(BaseModel): - name: str - description: Optional[str] = None - - -app = FastAPI(separate_input_output_schemas=False) - - -@app.post("/items/") -def create_item(item: Item): - return item - - -@app.get("/items/") -def read_items() -> list[Item]: - return [ - Item( - name="Portal Gun", - description="Device to travel through the multi-rick-verse", - ), - Item(name="Plumbus"), - ] diff --git a/docs_src/settings/app01_py310/__init__.py b/docs_src/settings/app01_py310/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/settings/app03_an_py39/config_pv1.py b/docs_src/settings/app01_py310/config.py similarity index 59% rename from docs_src/settings/app03_an_py39/config_pv1.py rename to docs_src/settings/app01_py310/config.py index 7ae66ef77..b31b8811d 100644 --- a/docs_src/settings/app03_an_py39/config_pv1.py +++ b/docs_src/settings/app01_py310/config.py @@ -1,4 +1,4 @@ -from pydantic.v1 import BaseSettings +from pydantic_settings import BaseSettings class Settings(BaseSettings): @@ -6,5 +6,5 @@ class Settings(BaseSettings): admin_email: str items_per_user: int = 50 - class Config: - env_file = ".env" + +settings = Settings() diff --git a/docs_src/settings/app01_py310/main.py b/docs_src/settings/app01_py310/main.py new file mode 100644 index 000000000..4a3a86ce2 --- /dev/null +++ b/docs_src/settings/app01_py310/main.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI + +from .config import settings + +app = FastAPI() + + +@app.get("/info") +async def info(): + return { + "app_name": settings.app_name, + "admin_email": settings.admin_email, + "items_per_user": settings.items_per_user, + } diff --git a/docs_src/settings/app02_an_py310/__init__.py b/docs_src/settings/app02_an_py310/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/settings/app03_py39/config_pv1.py b/docs_src/settings/app02_an_py310/config.py similarity index 58% rename from docs_src/settings/app03_py39/config_pv1.py rename to docs_src/settings/app02_an_py310/config.py index 7ae66ef77..e17b5035d 100644 --- a/docs_src/settings/app03_py39/config_pv1.py +++ b/docs_src/settings/app02_an_py310/config.py @@ -1,10 +1,7 @@ -from pydantic.v1 import BaseSettings +from pydantic_settings import BaseSettings class Settings(BaseSettings): app_name: str = "Awesome API" admin_email: str items_per_user: int = 50 - - class Config: - env_file = ".env" diff --git a/docs_src/settings/app02_an_py310/main.py b/docs_src/settings/app02_an_py310/main.py new file mode 100644 index 000000000..6d5db12a8 --- /dev/null +++ b/docs_src/settings/app02_an_py310/main.py @@ -0,0 +1,22 @@ +from functools import lru_cache +from typing import Annotated + +from fastapi import Depends, FastAPI + +from .config import Settings + +app = FastAPI() + + +@lru_cache +def get_settings(): + return Settings() + + +@app.get("/info") +async def info(settings: Annotated[Settings, Depends(get_settings)]): + return { + "app_name": settings.app_name, + "admin_email": settings.admin_email, + "items_per_user": settings.items_per_user, + } diff --git a/docs_src/settings/app02_an_py310/test_main.py b/docs_src/settings/app02_an_py310/test_main.py new file mode 100644 index 000000000..7a04d7e8e --- /dev/null +++ b/docs_src/settings/app02_an_py310/test_main.py @@ -0,0 +1,23 @@ +from fastapi.testclient import TestClient + +from .config import Settings +from .main import app, get_settings + +client = TestClient(app) + + +def get_settings_override(): + return Settings(admin_email="testing_admin@example.com") + + +app.dependency_overrides[get_settings] = get_settings_override + + +def test_app(): + response = client.get("/info") + data = response.json() + assert data == { + "app_name": "Awesome API", + "admin_email": "testing_admin@example.com", + "items_per_user": 50, + } diff --git a/docs_src/settings/app02_py310/__init__.py b/docs_src/settings/app02_py310/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/settings/app02_py310/config.py b/docs_src/settings/app02_py310/config.py new file mode 100644 index 000000000..e17b5035d --- /dev/null +++ b/docs_src/settings/app02_py310/config.py @@ -0,0 +1,7 @@ +from pydantic_settings import BaseSettings + + +class Settings(BaseSettings): + app_name: str = "Awesome API" + admin_email: str + items_per_user: int = 50 diff --git a/docs_src/settings/app02_py310/main.py b/docs_src/settings/app02_py310/main.py new file mode 100644 index 000000000..941f82e6b --- /dev/null +++ b/docs_src/settings/app02_py310/main.py @@ -0,0 +1,21 @@ +from functools import lru_cache + +from fastapi import Depends, FastAPI + +from .config import Settings + +app = FastAPI() + + +@lru_cache +def get_settings(): + return Settings() + + +@app.get("/info") +async def info(settings: Settings = Depends(get_settings)): + return { + "app_name": settings.app_name, + "admin_email": settings.admin_email, + "items_per_user": settings.items_per_user, + } diff --git a/docs_src/settings/app02_py310/test_main.py b/docs_src/settings/app02_py310/test_main.py new file mode 100644 index 000000000..7a04d7e8e --- /dev/null +++ b/docs_src/settings/app02_py310/test_main.py @@ -0,0 +1,23 @@ +from fastapi.testclient import TestClient + +from .config import Settings +from .main import app, get_settings + +client = TestClient(app) + + +def get_settings_override(): + return Settings(admin_email="testing_admin@example.com") + + +app.dependency_overrides[get_settings] = get_settings_override + + +def test_app(): + response = client.get("/info") + data = response.json() + assert data == { + "app_name": "Awesome API", + "admin_email": "testing_admin@example.com", + "items_per_user": 50, + } diff --git a/docs_src/settings/app03_an_py310/__init__.py b/docs_src/settings/app03_an_py310/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/settings/app03_an_py310/config.py b/docs_src/settings/app03_an_py310/config.py new file mode 100644 index 000000000..08f8f88c2 --- /dev/null +++ b/docs_src/settings/app03_an_py310/config.py @@ -0,0 +1,9 @@ +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class Settings(BaseSettings): + app_name: str = "Awesome API" + admin_email: str + items_per_user: int = 50 + + model_config = SettingsConfigDict(env_file=".env") diff --git a/docs_src/settings/app03_an_py310/main.py b/docs_src/settings/app03_an_py310/main.py new file mode 100644 index 000000000..2f64b9cd1 --- /dev/null +++ b/docs_src/settings/app03_an_py310/main.py @@ -0,0 +1,22 @@ +from functools import lru_cache +from typing import Annotated + +from fastapi import Depends, FastAPI + +from . import config + +app = FastAPI() + + +@lru_cache +def get_settings(): + return config.Settings() + + +@app.get("/info") +async def info(settings: Annotated[config.Settings, Depends(get_settings)]): + return { + "app_name": settings.app_name, + "admin_email": settings.admin_email, + "items_per_user": settings.items_per_user, + } diff --git a/docs_src/settings/app03_py310/__init__.py b/docs_src/settings/app03_py310/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/docs_src/settings/app03_py310/config.py b/docs_src/settings/app03_py310/config.py new file mode 100644 index 000000000..08f8f88c2 --- /dev/null +++ b/docs_src/settings/app03_py310/config.py @@ -0,0 +1,9 @@ +from pydantic_settings import BaseSettings, SettingsConfigDict + + +class Settings(BaseSettings): + app_name: str = "Awesome API" + admin_email: str + items_per_user: int = 50 + + model_config = SettingsConfigDict(env_file=".env") diff --git a/docs_src/settings/app03_py310/main.py b/docs_src/settings/app03_py310/main.py new file mode 100644 index 000000000..ea64a5709 --- /dev/null +++ b/docs_src/settings/app03_py310/main.py @@ -0,0 +1,21 @@ +from functools import lru_cache + +from fastapi import Depends, FastAPI + +from . import config + +app = FastAPI() + + +@lru_cache +def get_settings(): + return config.Settings() + + +@app.get("/info") +async def info(settings: config.Settings = Depends(get_settings)): + return { + "app_name": settings.app_name, + "admin_email": settings.admin_email, + "items_per_user": settings.items_per_user, + } diff --git a/docs_src/settings/tutorial001_pv1_py39.py b/docs_src/settings/tutorial001_py310.py similarity index 89% rename from docs_src/settings/tutorial001_pv1_py39.py rename to docs_src/settings/tutorial001_py310.py index 20ad2bbf6..d48c4c060 100644 --- a/docs_src/settings/tutorial001_pv1_py39.py +++ b/docs_src/settings/tutorial001_py310.py @@ -1,5 +1,5 @@ from fastapi import FastAPI -from pydantic.v1 import BaseSettings +from pydantic_settings import BaseSettings class Settings(BaseSettings): diff --git a/docs_src/sql_databases/tutorial001_an_py39.py b/docs_src/sql_databases/tutorial001_an_py39.py deleted file mode 100644 index 595892746..000000000 --- a/docs_src/sql_databases/tutorial001_an_py39.py +++ /dev/null @@ -1,73 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI, HTTPException, Query -from sqlmodel import Field, Session, SQLModel, create_engine, select - - -class Hero(SQLModel, table=True): - id: Union[int, None] = Field(default=None, primary_key=True) - name: str = Field(index=True) - age: Union[int, None] = Field(default=None, index=True) - secret_name: str - - -sqlite_file_name = "database.db" -sqlite_url = f"sqlite:///{sqlite_file_name}" - -connect_args = {"check_same_thread": False} -engine = create_engine(sqlite_url, connect_args=connect_args) - - -def create_db_and_tables(): - SQLModel.metadata.create_all(engine) - - -def get_session(): - with Session(engine) as session: - yield session - - -SessionDep = Annotated[Session, Depends(get_session)] - -app = FastAPI() - - -@app.on_event("startup") -def on_startup(): - create_db_and_tables() - - -@app.post("/heroes/") -def create_hero(hero: Hero, session: SessionDep) -> Hero: - session.add(hero) - session.commit() - session.refresh(hero) - return hero - - -@app.get("/heroes/") -def read_heroes( - session: SessionDep, - offset: int = 0, - limit: Annotated[int, Query(le=100)] = 100, -) -> list[Hero]: - heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() - return heroes - - -@app.get("/heroes/{hero_id}") -def read_hero(hero_id: int, session: SessionDep) -> Hero: - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - return hero - - -@app.delete("/heroes/{hero_id}") -def delete_hero(hero_id: int, session: SessionDep): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - session.delete(hero) - session.commit() - return {"ok": True} diff --git a/docs_src/sql_databases/tutorial001_py39.py b/docs_src/sql_databases/tutorial001_py39.py deleted file mode 100644 index 410a52d0c..000000000 --- a/docs_src/sql_databases/tutorial001_py39.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI, HTTPException, Query -from sqlmodel import Field, Session, SQLModel, create_engine, select - - -class Hero(SQLModel, table=True): - id: Union[int, None] = Field(default=None, primary_key=True) - name: str = Field(index=True) - age: Union[int, None] = Field(default=None, index=True) - secret_name: str - - -sqlite_file_name = "database.db" -sqlite_url = f"sqlite:///{sqlite_file_name}" - -connect_args = {"check_same_thread": False} -engine = create_engine(sqlite_url, connect_args=connect_args) - - -def create_db_and_tables(): - SQLModel.metadata.create_all(engine) - - -def get_session(): - with Session(engine) as session: - yield session - - -app = FastAPI() - - -@app.on_event("startup") -def on_startup(): - create_db_and_tables() - - -@app.post("/heroes/") -def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero: - session.add(hero) - session.commit() - session.refresh(hero) - return hero - - -@app.get("/heroes/") -def read_heroes( - session: Session = Depends(get_session), - offset: int = 0, - limit: int = Query(default=100, le=100), -) -> list[Hero]: - heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() - return heroes - - -@app.get("/heroes/{hero_id}") -def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero: - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - return hero - - -@app.delete("/heroes/{hero_id}") -def delete_hero(hero_id: int, session: Session = Depends(get_session)): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - session.delete(hero) - session.commit() - return {"ok": True} diff --git a/docs_src/sql_databases/tutorial002_an_py39.py b/docs_src/sql_databases/tutorial002_an_py39.py deleted file mode 100644 index a8a0721ff..000000000 --- a/docs_src/sql_databases/tutorial002_an_py39.py +++ /dev/null @@ -1,103 +0,0 @@ -from typing import Annotated, Union - -from fastapi import Depends, FastAPI, HTTPException, Query -from sqlmodel import Field, Session, SQLModel, create_engine, select - - -class HeroBase(SQLModel): - name: str = Field(index=True) - age: Union[int, None] = Field(default=None, index=True) - - -class Hero(HeroBase, table=True): - id: Union[int, None] = Field(default=None, primary_key=True) - secret_name: str - - -class HeroPublic(HeroBase): - id: int - - -class HeroCreate(HeroBase): - secret_name: str - - -class HeroUpdate(HeroBase): - name: Union[str, None] = None - age: Union[int, None] = None - secret_name: Union[str, None] = None - - -sqlite_file_name = "database.db" -sqlite_url = f"sqlite:///{sqlite_file_name}" - -connect_args = {"check_same_thread": False} -engine = create_engine(sqlite_url, connect_args=connect_args) - - -def create_db_and_tables(): - SQLModel.metadata.create_all(engine) - - -def get_session(): - with Session(engine) as session: - yield session - - -SessionDep = Annotated[Session, Depends(get_session)] -app = FastAPI() - - -@app.on_event("startup") -def on_startup(): - create_db_and_tables() - - -@app.post("/heroes/", response_model=HeroPublic) -def create_hero(hero: HeroCreate, session: SessionDep): - db_hero = Hero.model_validate(hero) - session.add(db_hero) - session.commit() - session.refresh(db_hero) - return db_hero - - -@app.get("/heroes/", response_model=list[HeroPublic]) -def read_heroes( - session: SessionDep, - offset: int = 0, - limit: Annotated[int, Query(le=100)] = 100, -): - heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() - return heroes - - -@app.get("/heroes/{hero_id}", response_model=HeroPublic) -def read_hero(hero_id: int, session: SessionDep): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - return hero - - -@app.patch("/heroes/{hero_id}", response_model=HeroPublic) -def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep): - hero_db = session.get(Hero, hero_id) - if not hero_db: - raise HTTPException(status_code=404, detail="Hero not found") - hero_data = hero.model_dump(exclude_unset=True) - hero_db.sqlmodel_update(hero_data) - session.add(hero_db) - session.commit() - session.refresh(hero_db) - return hero_db - - -@app.delete("/heroes/{hero_id}") -def delete_hero(hero_id: int, session: SessionDep): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - session.delete(hero) - session.commit() - return {"ok": True} diff --git a/docs_src/sql_databases/tutorial002_py39.py b/docs_src/sql_databases/tutorial002_py39.py deleted file mode 100644 index d8f5dd090..000000000 --- a/docs_src/sql_databases/tutorial002_py39.py +++ /dev/null @@ -1,104 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI, HTTPException, Query -from sqlmodel import Field, Session, SQLModel, create_engine, select - - -class HeroBase(SQLModel): - name: str = Field(index=True) - age: Union[int, None] = Field(default=None, index=True) - - -class Hero(HeroBase, table=True): - id: Union[int, None] = Field(default=None, primary_key=True) - secret_name: str - - -class HeroPublic(HeroBase): - id: int - - -class HeroCreate(HeroBase): - secret_name: str - - -class HeroUpdate(HeroBase): - name: Union[str, None] = None - age: Union[int, None] = None - secret_name: Union[str, None] = None - - -sqlite_file_name = "database.db" -sqlite_url = f"sqlite:///{sqlite_file_name}" - -connect_args = {"check_same_thread": False} -engine = create_engine(sqlite_url, connect_args=connect_args) - - -def create_db_and_tables(): - SQLModel.metadata.create_all(engine) - - -def get_session(): - with Session(engine) as session: - yield session - - -app = FastAPI() - - -@app.on_event("startup") -def on_startup(): - create_db_and_tables() - - -@app.post("/heroes/", response_model=HeroPublic) -def create_hero(hero: HeroCreate, session: Session = Depends(get_session)): - db_hero = Hero.model_validate(hero) - session.add(db_hero) - session.commit() - session.refresh(db_hero) - return db_hero - - -@app.get("/heroes/", response_model=list[HeroPublic]) -def read_heroes( - session: Session = Depends(get_session), - offset: int = 0, - limit: int = Query(default=100, le=100), -): - heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() - return heroes - - -@app.get("/heroes/{hero_id}", response_model=HeroPublic) -def read_hero(hero_id: int, session: Session = Depends(get_session)): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - return hero - - -@app.patch("/heroes/{hero_id}", response_model=HeroPublic) -def update_hero( - hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session) -): - hero_db = session.get(Hero, hero_id) - if not hero_db: - raise HTTPException(status_code=404, detail="Hero not found") - hero_data = hero.model_dump(exclude_unset=True) - hero_db.sqlmodel_update(hero_data) - session.add(hero_db) - session.commit() - session.refresh(hero_db) - return hero_db - - -@app.delete("/heroes/{hero_id}") -def delete_hero(hero_id: int, session: Session = Depends(get_session)): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - session.delete(hero) - session.commit() - return {"ok": True} diff --git a/docs_src/static_files/tutorial001_py310.py b/docs_src/static_files/tutorial001_py310.py new file mode 100644 index 000000000..460352c7e --- /dev/null +++ b/docs_src/static_files/tutorial001_py310.py @@ -0,0 +1,6 @@ +from fastapi import FastAPI +from fastapi.staticfiles import StaticFiles + +app = FastAPI() + +app.mount("/static", StaticFiles(directory="static"), name="static") diff --git a/docs_src/sub_applications/tutorial001_py310.py b/docs_src/sub_applications/tutorial001_py310.py new file mode 100644 index 000000000..57e627e80 --- /dev/null +++ b/docs_src/sub_applications/tutorial001_py310.py @@ -0,0 +1,19 @@ +from fastapi import FastAPI + +app = FastAPI() + + +@app.get("/app") +def read_main(): + return {"message": "Hello World from main app"} + + +subapi = FastAPI() + + +@subapi.get("/sub") +def read_sub(): + return {"message": "Hello World from sub API"} + + +app.mount("/subapi", subapi) diff --git a/docs_src/templates/tutorial001_py310.py b/docs_src/templates/tutorial001_py310.py new file mode 100644 index 000000000..81ccc8d4d --- /dev/null +++ b/docs_src/templates/tutorial001_py310.py @@ -0,0 +1,18 @@ +from fastapi import FastAPI, Request +from fastapi.responses import HTMLResponse +from fastapi.staticfiles import StaticFiles +from fastapi.templating import Jinja2Templates + +app = FastAPI() + +app.mount("/static", StaticFiles(directory="static"), name="static") + + +templates = Jinja2Templates(directory="templates") + + +@app.get("/items/{id}", response_class=HTMLResponse) +async def read_item(request: Request, id: str): + return templates.TemplateResponse( + request=request, name="item.html", context={"id": id} + ) diff --git a/docs_src/using_request_directly/tutorial001_py310.py b/docs_src/using_request_directly/tutorial001_py310.py new file mode 100644 index 000000000..2d7288b54 --- /dev/null +++ b/docs_src/using_request_directly/tutorial001_py310.py @@ -0,0 +1,9 @@ +from fastapi import FastAPI, Request + +app = FastAPI() + + +@app.get("/items/{item_id}") +def read_root(item_id: str, request: Request): + client_host = request.client.host + return {"client_host": client_host, "item_id": item_id} diff --git a/docs_src/websockets/tutorial001_py310.py b/docs_src/websockets/tutorial001_py310.py new file mode 100644 index 000000000..a43a2be17 --- /dev/null +++ b/docs_src/websockets/tutorial001_py310.py @@ -0,0 +1,51 @@ +from fastapi import FastAPI, WebSocket +from fastapi.responses import HTMLResponse + +app = FastAPI() + +html = """ + + + + Chat + + +

WebSocket Chat

+
+ + +
+ + + + +""" + + +@app.get("/") +async def get(): + return HTMLResponse(html) + + +@app.websocket("/ws") +async def websocket_endpoint(websocket: WebSocket): + await websocket.accept() + while True: + data = await websocket.receive_text() + await websocket.send_text(f"Message text was: {data}") diff --git a/docs_src/websockets/tutorial002_an_py39.py b/docs_src/websockets/tutorial002_an_py39.py deleted file mode 100644 index 606d355fe..000000000 --- a/docs_src/websockets/tutorial002_an_py39.py +++ /dev/null @@ -1,92 +0,0 @@ -from typing import Annotated, Union - -from fastapi import ( - Cookie, - Depends, - FastAPI, - Query, - WebSocket, - WebSocketException, - status, -) -from fastapi.responses import HTMLResponse - -app = FastAPI() - -html = """ - - - - Chat - - -

WebSocket Chat

-
- - - -
- - -
- - - - -""" - - -@app.get("/") -async def get(): - return HTMLResponse(html) - - -async def get_cookie_or_token( - websocket: WebSocket, - session: Annotated[Union[str, None], Cookie()] = None, - token: Annotated[Union[str, None], Query()] = None, -): - if session is None and token is None: - raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION) - return session or token - - -@app.websocket("/items/{item_id}/ws") -async def websocket_endpoint( - *, - websocket: WebSocket, - item_id: str, - q: Union[int, None] = None, - cookie_or_token: Annotated[str, Depends(get_cookie_or_token)], -): - await websocket.accept() - while True: - data = await websocket.receive_text() - await websocket.send_text( - f"Session cookie or query token value is: {cookie_or_token}" - ) - if q is not None: - await websocket.send_text(f"Query parameter q is: {q}") - await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}") diff --git a/docs_src/websockets/tutorial002_py39.py b/docs_src/websockets/tutorial002_py39.py deleted file mode 100644 index cab749e4d..000000000 --- a/docs_src/websockets/tutorial002_py39.py +++ /dev/null @@ -1,91 +0,0 @@ -from typing import Union - -from fastapi import ( - Cookie, - Depends, - FastAPI, - Query, - WebSocket, - WebSocketException, - status, -) -from fastapi.responses import HTMLResponse - -app = FastAPI() - -html = """ - - - - Chat - - -

WebSocket Chat

-
- - - -
- - -
- - - - -""" - - -@app.get("/") -async def get(): - return HTMLResponse(html) - - -async def get_cookie_or_token( - websocket: WebSocket, - session: Union[str, None] = Cookie(default=None), - token: Union[str, None] = Query(default=None), -): - if session is None and token is None: - raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION) - return session or token - - -@app.websocket("/items/{item_id}/ws") -async def websocket_endpoint( - websocket: WebSocket, - item_id: str, - q: Union[int, None] = None, - cookie_or_token: str = Depends(get_cookie_or_token), -): - await websocket.accept() - while True: - data = await websocket.receive_text() - await websocket.send_text( - f"Session cookie or query token value is: {cookie_or_token}" - ) - if q is not None: - await websocket.send_text(f"Query parameter q is: {q}") - await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}") diff --git a/docs_src/websockets/tutorial003_py310.py b/docs_src/websockets/tutorial003_py310.py new file mode 100644 index 000000000..316218088 --- /dev/null +++ b/docs_src/websockets/tutorial003_py310.py @@ -0,0 +1,81 @@ +from fastapi import FastAPI, WebSocket, WebSocketDisconnect +from fastapi.responses import HTMLResponse + +app = FastAPI() + +html = """ + + + + Chat + + +

WebSocket Chat

+

Your ID:

+
+ + +
+ + + + +""" + + +class ConnectionManager: + def __init__(self): + self.active_connections: list[WebSocket] = [] + + async def connect(self, websocket: WebSocket): + await websocket.accept() + self.active_connections.append(websocket) + + def disconnect(self, websocket: WebSocket): + self.active_connections.remove(websocket) + + async def send_personal_message(self, message: str, websocket: WebSocket): + await websocket.send_text(message) + + async def broadcast(self, message: str): + for connection in self.active_connections: + await connection.send_text(message) + + +manager = ConnectionManager() + + +@app.get("/") +async def get(): + return HTMLResponse(html) + + +@app.websocket("/ws/{client_id}") +async def websocket_endpoint(websocket: WebSocket, client_id: int): + await manager.connect(websocket) + try: + while True: + data = await websocket.receive_text() + await manager.send_personal_message(f"You wrote: {data}", websocket) + await manager.broadcast(f"Client #{client_id} says: {data}") + except WebSocketDisconnect: + manager.disconnect(websocket) + await manager.broadcast(f"Client #{client_id} left the chat") diff --git a/docs_src/wsgi/tutorial001_py310.py b/docs_src/wsgi/tutorial001_py310.py new file mode 100644 index 000000000..8eeceb829 --- /dev/null +++ b/docs_src/wsgi/tutorial001_py310.py @@ -0,0 +1,23 @@ +from a2wsgi import WSGIMiddleware +from fastapi import FastAPI +from flask import Flask, request +from markupsafe import escape + +flask_app = Flask(__name__) + + +@flask_app.route("/") +def flask_main(): + name = request.args.get("name", "World") + return f"Hello, {escape(name)} from Flask!" + + +app = FastAPI() + + +@app.get("/v2") +def read_main(): + return {"message": "Hello World"} + + +app.mount("/v1", WSGIMiddleware(flask_app)) diff --git a/pyproject.toml b/pyproject.toml index e1ce30507..a6708064d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -327,32 +327,42 @@ ignore = [ [tool.ruff.lint.per-file-ignores] "__init__.py" = ["F401"] -"docs_src/dependencies/tutorial007_py39.py" = ["F821"] -"docs_src/dependencies/tutorial008_py39.py" = ["F821"] -"docs_src/dependencies/tutorial009_py39.py" = ["F821"] -"docs_src/dependencies/tutorial010_py39.py" = ["F821"] +"docs_src/custom_request_and_route/tutorial002_an_py310.py" = ["B904"] +"docs_src/custom_request_and_route/tutorial002_an_py39.py" = ["B904"] +"docs_src/custom_request_and_route/tutorial002_py310.py" = ["B904"] +"docs_src/custom_request_and_route/tutorial002_py39.py" = ["B904"] +"docs_src/custom_response/tutorial007_py310.py" = ["B007"] "docs_src/custom_response/tutorial007_py39.py" = ["B007"] "docs_src/dataclasses/tutorial003_py39.py" = ["I001"] -"docs_src/path_operation_advanced_configuration/tutorial007_py39.py" = ["B904"] -"docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py" = ["B904"] -"docs_src/custom_request_and_route/tutorial002_py39.py" = ["B904"] -"docs_src/custom_request_and_route/tutorial002_py310.py" = ["B904"] -"docs_src/custom_request_and_route/tutorial002_an_py39.py" = ["B904"] -"docs_src/custom_request_and_route/tutorial002_an_py310.py" = ["B904"] +"docs_src/dependencies/tutorial007_py310.py" = ["F821"] +"docs_src/dependencies/tutorial007_py39.py" = ["F821"] +"docs_src/dependencies/tutorial008_an_py310.py" = ["F821"] "docs_src/dependencies/tutorial008_an_py39.py" = ["F821"] +"docs_src/dependencies/tutorial008_py310.py" = ["F821"] +"docs_src/dependencies/tutorial008_py39.py" = ["F821"] +"docs_src/dependencies/tutorial008b_an_py310.py" = ["B904"] +"docs_src/dependencies/tutorial008b_an_py39.py" = ["B904"] +"docs_src/dependencies/tutorial008b_py310.py" = ["B904"] +"docs_src/dependencies/tutorial008b_py39.py" = ["B904"] +"docs_src/dependencies/tutorial009_py310.py" = ["F821"] +"docs_src/dependencies/tutorial009_py39.py" = ["F821"] +"docs_src/dependencies/tutorial010_py310.py" = ["F821"] +"docs_src/dependencies/tutorial010_py39.py" = ["F821"] +"docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py" = ["B904"] +"docs_src/path_operation_advanced_configuration/tutorial007_py310.py" = ["B904"] +"docs_src/path_operation_advanced_configuration/tutorial007_py39.py" = ["B904"] +"docs_src/query_params_str_validations/tutorial012_an_py310.py" = ["B006"] "docs_src/query_params_str_validations/tutorial012_an_py39.py" = ["B006"] +"docs_src/query_params_str_validations/tutorial013_an_py310.py" = ["B006"] "docs_src/query_params_str_validations/tutorial013_an_py39.py" = ["B006"] -"docs_src/security/tutorial004_py39.py" = ["B904"] -"docs_src/security/tutorial004_an_py39.py" = ["B904"] "docs_src/security/tutorial004_an_py310.py" = ["B904"] +"docs_src/security/tutorial004_an_py39.py" = ["B904"] "docs_src/security/tutorial004_py310.py" = ["B904"] +"docs_src/security/tutorial004_py39.py" = ["B904"] "docs_src/security/tutorial005_an_py310.py" = ["B904"] "docs_src/security/tutorial005_an_py39.py" = ["B904"] "docs_src/security/tutorial005_py310.py" = ["B904"] "docs_src/security/tutorial005_py39.py" = ["B904"] -"docs_src/dependencies/tutorial008b_py39.py" = ["B904"] -"docs_src/dependencies/tutorial008b_an_py39.py" = ["B904"] - [tool.ruff.lint.isort] known-third-party = ["fastapi", "pydantic", "starlette"]