diff --git a/docs/en/docs/_llm-test.md b/docs/en/docs/_llm-test.md index 2b548064d..946443e68 100644 --- a/docs/en/docs/_llm-test.md +++ b/docs/en/docs/_llm-test.md @@ -185,7 +185,7 @@ See section `### Links` in the general prompt in `scripts/translate.py`. //// tab | Test -Here some things wrapped in HTML "abbr" elements (Some are invented): +Here are some things wrapped in HTML "abbr" elements (Some are invented): ### The abbr gives a full phrase { #the-abbr-gives-a-full-phrase } diff --git a/docs/en/docs/advanced/additional-status-codes.md b/docs/en/docs/advanced/additional-status-codes.md index 3b6da2355..c4f1bf389 100644 --- a/docs/en/docs/advanced/additional-status-codes.md +++ b/docs/en/docs/advanced/additional-status-codes.md @@ -8,7 +8,7 @@ It will use the default status code or the one you set in your *path operation*. If you want to return additional status codes apart from the main one, you can do that by returning a `Response` directly, like a `JSONResponse`, and set the additional status code directly. -For example, let's say that you want to have a *path operation* that allows to update items, and returns HTTP status codes of 200 "OK" when successful. +For example, let's say that you want to have a *path operation* that allows updating items, and returns HTTP status codes of 200 "OK" when successful. But you also want it to accept new items. And when the items didn't exist before, it creates them, and returns an HTTP status code of 201 "Created". diff --git a/docs/en/docs/advanced/advanced-dependencies.md b/docs/en/docs/advanced/advanced-dependencies.md index 59ab62bf0..030fe8548 100644 --- a/docs/en/docs/advanced/advanced-dependencies.md +++ b/docs/en/docs/advanced/advanced-dependencies.md @@ -54,7 +54,7 @@ checker(q="somequery") /// tip -All this might seem contrived. And it might not be very clear how is it useful yet. +All this might seem contrived. And it might not be very clear how it is useful yet. These examples are intentionally simple, but show how it all works. diff --git a/docs/en/docs/advanced/dataclasses.md b/docs/en/docs/advanced/dataclasses.md index 292dc3fba..fbabe0c87 100644 --- a/docs/en/docs/advanced/dataclasses.md +++ b/docs/en/docs/advanced/dataclasses.md @@ -24,7 +24,7 @@ Keep in mind that dataclasses can't do everything Pydantic models can do. So, you might still need to use Pydantic models. -But if you have a bunch of dataclasses laying around, this is a nice trick to use them to power a web API using FastAPI. πŸ€“ +But if you have a bunch of dataclasses lying around, this is a nice trick to use them to power a web API using FastAPI. πŸ€“ /// diff --git a/docs/en/docs/advanced/json-base64-bytes.md b/docs/en/docs/advanced/json-base64-bytes.md index 9f0602c54..55f4a99b4 100644 --- a/docs/en/docs/advanced/json-base64-bytes.md +++ b/docs/en/docs/advanced/json-base64-bytes.md @@ -4,7 +4,7 @@ If your app needs to receive and send JSON data, but you need to include binary ## Base64 vs Files { #base64-vs-files } -Consider first if you can use [Request Files](../tutorial/request-files.md) for uploading binary data and [Custom Response - FileResponse](./custom-response.md#fileresponse--fileresponse-) for sending binary data, instead of encoding it in JSON. +Consider first if you can use [Request Files](../tutorial/request-files.md) for uploading binary data and [Custom Response - FileResponse](./custom-response.md#fileresponse) for sending binary data, instead of encoding it in JSON. JSON can only contain UTF-8 encoded strings, so it can't contain raw bytes. diff --git a/docs/en/docs/advanced/openapi-callbacks.md b/docs/en/docs/advanced/openapi-callbacks.md index 40cf47956..e8ff01696 100644 --- a/docs/en/docs/advanced/openapi-callbacks.md +++ b/docs/en/docs/advanced/openapi-callbacks.md @@ -173,7 +173,7 @@ Now use the parameter `callbacks` in *your API's path operation decorator* to pa /// tip -Notice that you are not passing the router itself (`invoices_callback_router`) to `callback=`, but the attribute `.routes`, as in `invoices_callback_router.routes`. +Notice that you are not passing the router itself (`invoices_callback_router`) to `callbacks=`, but the attribute `.routes`, as in `invoices_callback_router.routes`. /// diff --git a/docs/en/docs/advanced/response-change-status-code.md b/docs/en/docs/advanced/response-change-status-code.md index 8efd63198..301688943 100644 --- a/docs/en/docs/advanced/response-change-status-code.md +++ b/docs/en/docs/advanced/response-change-status-code.md @@ -18,7 +18,7 @@ For those cases, you can use a `Response` parameter. You can declare a parameter of type `Response` in your *path operation function* (as you can do for cookies and headers). -And then you can set the `status_code` in that *temporal* response object. +And then you can set the `status_code` in that *temporary* response object. {* ../../docs_src/response_change_status_code/tutorial001_py310.py hl[1,9,12] *} diff --git a/docs/en/docs/advanced/response-cookies.md b/docs/en/docs/advanced/response-cookies.md index a7ad90cad..904ac26fd 100644 --- a/docs/en/docs/advanced/response-cookies.md +++ b/docs/en/docs/advanced/response-cookies.md @@ -4,7 +4,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. +And then you can set cookies in that *temporary* response object. {* ../../docs_src/response_cookies/tutorial002_py310.py hl[1, 8:9] *} diff --git a/docs/en/docs/advanced/response-headers.md b/docs/en/docs/advanced/response-headers.md index d7738635d..49032c800 100644 --- a/docs/en/docs/advanced/response-headers.md +++ b/docs/en/docs/advanced/response-headers.md @@ -4,7 +4,7 @@ You can declare a parameter of type `Response` in your *path operation function* (as you can do for cookies). -And then you can set headers in that *temporal* response object. +And then you can set headers in that *temporary* response object. {* ../../docs_src/response_headers/tutorial002_py310.py hl[1, 7:8] *} diff --git a/docs/en/docs/advanced/security/oauth2-scopes.md b/docs/en/docs/advanced/security/oauth2-scopes.md index 92b604757..9346cd545 100644 --- a/docs/en/docs/advanced/security/oauth2-scopes.md +++ b/docs/en/docs/advanced/security/oauth2-scopes.md @@ -194,7 +194,7 @@ For this, we use `security_scopes.scopes`, that contains a `list` with all these Let's review again this dependency tree and the scopes. -As the `get_current_active_user` dependency has as a sub-dependency on `get_current_user`, the scope `"me"` declared at `get_current_active_user` will be included in the list of required scopes in the `security_scopes.scopes` passed to `get_current_user`. +As the `get_current_active_user` dependency has `get_current_user` as a sub-dependency, the scope `"me"` declared at `get_current_active_user` will be included in the list of required scopes in the `security_scopes.scopes` passed to `get_current_user`. The *path operation* itself also declares a scope, `"items"`, so this will also be in the list of `security_scopes.scopes` passed to `get_current_user`. diff --git a/docs/en/docs/advanced/settings.md b/docs/en/docs/advanced/settings.md index f0f3bb41d..ff313f088 100644 --- a/docs/en/docs/advanced/settings.md +++ b/docs/en/docs/advanced/settings.md @@ -14,7 +14,7 @@ To understand environment variables you can read [Environment Variables](../envi ## Types and validation { #types-and-validation } -These environment variables can only handle text strings, as they are external to Python and have to be compatible with other programs and the rest of the system (and even with different operating systems, as Linux, Windows, macOS). +These environment variables can only handle text strings, as they are external to Python and have to be compatible with other programs and the rest of the system (and even with different operating systems, such as Linux, Windows, and macOS). That means that any value read in Python from an environment variable will be a `str`, and any conversion to a different type or any validation has to be done in code. diff --git a/docs/en/docs/advanced/stream-data.md b/docs/en/docs/advanced/stream-data.md index 3e7c89a93..40ea33743 100644 --- a/docs/en/docs/advanced/stream-data.md +++ b/docs/en/docs/advanced/stream-data.md @@ -14,7 +14,7 @@ Added in FastAPI 0.134.0. You could use this if you want to stream pure strings, for example directly from the output of an **AI LLM** service. -You could also use it to stream **large binary files**, where you stream each chunk of data as you read it, without having to read it all in memory at once. +You could also use it to stream **large binary files**, where you stream each chunk of data as you read it, without having to read it all into memory at once. You could also stream **video** or **audio** this way, it could even be generated as you process and send it. diff --git a/docs/en/docs/advanced/wsgi.md b/docs/en/docs/advanced/wsgi.md index 39a492eb6..8dcc3c401 100644 --- a/docs/en/docs/advanced/wsgi.md +++ b/docs/en/docs/advanced/wsgi.md @@ -24,7 +24,7 @@ And then mount that under a path. Previously, it was recommended to use `WSGIMiddleware` from `fastapi.middleware.wsgi`, but it is now deprecated. -It’s advised to use the `a2wsgi` package instead. The usage remains the same. +It's advised to use the `a2wsgi` package instead. The usage remains the same. Just ensure that you have the `a2wsgi` package installed and import `WSGIMiddleware` correctly from `a2wsgi`. diff --git a/docs/en/docs/alternatives.md b/docs/en/docs/alternatives.md index 0e7dc8571..d4942a37b 100644 --- a/docs/en/docs/alternatives.md +++ b/docs/en/docs/alternatives.md @@ -24,7 +24,7 @@ It was created to generate the HTML in the backend, not to create APIs used by a ### [Django REST Framework](https://www.django-rest-framework.org/) { #django-rest-framework } -Django REST framework was created to be a flexible toolkit for building Web APIs using Django underneath, to improve its API capabilities. +Django REST Framework was created to be a flexible toolkit for building Web APIs using Django underneath, to improve its API capabilities. It is used by many companies including Mozilla, Red Hat and Eventbrite. @@ -345,7 +345,7 @@ Hug was created by Timothy Crosley, the same creator of [`isort`](https://github Hug inspired parts of APIStar, and was one of the tools I found most promising, alongside APIStar. -Hug helped inspiring **FastAPI** to use Python type hints to declare parameters, and to generate a schema defining the API automatically. +Hug helped inspire **FastAPI** to use Python type hints to declare parameters, and to generate a schema defining the API automatically. Hug inspired **FastAPI** to declare a `response` parameter in functions to set headers and cookies. @@ -380,7 +380,7 @@ Now APIStar is a set of tools to validate OpenAPI specifications, not a web fram APIStar was created by Tom Christie. The same guy that created: * Django REST Framework -* Starlette (in which **FastAPI** is based) +* Starlette (on which **FastAPI** is based) * Uvicorn (used by Starlette and **FastAPI**) /// @@ -393,7 +393,7 @@ The idea of declaring multiple things (data validation, serialization and docume And after searching for a long time for a similar framework and testing many different alternatives, APIStar was the best option available. -Then APIStar stopped to exist as a server and Starlette was created, and was a new better foundation for such a system. That was the final inspiration to build **FastAPI**. +Then APIStar stopped existing as a server and Starlette was created, and was a new better foundation for such a system. That was the final inspiration to build **FastAPI**. I consider **FastAPI** a "spiritual successor" to APIStar, while improving and increasing the features, typing system, and other parts, based on the learnings from all these previous tools. diff --git a/docs/en/docs/async.md b/docs/en/docs/async.md index 1ad996034..d975ddb53 100644 --- a/docs/en/docs/async.md +++ b/docs/en/docs/async.md @@ -70,7 +70,7 @@ Asynchronous code just means that the language πŸ’¬ has a way to tell the comput So, during that time, the computer can go and do some other work, while "slow-file" πŸ“ finishes. -Then the computer / program πŸ€– will come back every time it has a chance because it's waiting again, or whenever it πŸ€– finished all the work it had at that point. And it πŸ€– will see if any of the tasks it was waiting for have already finished, doing whatever it had to do. +Then the computer / program πŸ€– will come back every time it has a chance because it's waiting again, or whenever it πŸ€– finishes all the work it had at that point. And it πŸ€– will see if any of the tasks it was waiting for have already finished, doing whatever it had to do. Next, it πŸ€– takes the first task to finish (let's say, our "slow-file" πŸ“) and continues whatever it had to do with it. @@ -78,7 +78,7 @@ That "wait for something else" normally refers to Ctrl + Shift + P or on macOS: Cmd + Shift + P) and selecting "Welcome: Open walkthrough..." and then choosing the "Get started with FastAPI" walkthrough. +If you'd like to familiarize yourself with the extension's features, you can check out the extension walkthrough by opening the Command Palette (Ctrl + Shift + P or on macOS: Cmd + Shift + P) and selecting "Welcome: Open walkthrough..." and then choosing the "Get started with FastAPI" walkthrough. diff --git a/docs/en/docs/environment-variables.md b/docs/en/docs/environment-variables.md index 010e27c37..b12369431 100644 --- a/docs/en/docs/environment-variables.md +++ b/docs/en/docs/environment-variables.md @@ -159,7 +159,7 @@ You can read more about it at [The Twelve-Factor App: Config](https://12factor.n ## Types and Validation { #types-and-validation } -These environment variables can only handle **text strings**, as they are external to Python and have to be compatible with other programs and the rest of the system (and even with different operating systems, as Linux, Windows, macOS). +These environment variables can only handle **text strings**, as they are external to Python and have to be compatible with other programs and the rest of the system (and even with different operating systems, such as Linux, Windows, and macOS). That means that **any value** read in Python from an environment variable **will be a `str`**, and any conversion to a different type or any validation has to be done in code. diff --git a/docs/en/docs/external-links.md b/docs/en/docs/external-links.md index e1614e818..d614c64eb 100644 --- a/docs/en/docs/external-links.md +++ b/docs/en/docs/external-links.md @@ -7,7 +7,7 @@ include_yaml: **FastAPI** has a great community constantly growing. -There are many posts, articles, tools, and projects, related to **FastAPI**. +There are many posts, articles, tools, and projects related to **FastAPI**. You could easily use a search engine or video platform to find many resources related to FastAPI. diff --git a/docs/en/docs/fastapi-people.md b/docs/en/docs/fastapi-people.md index ad32966e5..5ad3d6eb7 100644 --- a/docs/en/docs/fastapi-people.md +++ b/docs/en/docs/fastapi-people.md @@ -54,7 +54,7 @@ A round of applause to them. πŸ‘ πŸ™‡ This is the current list of team members. 😎 -They have different levels of involvement and permissions, they can perform [repository management tasks](./management-tasks.md) and together we [manage the FastAPI repository](./management.md). +They have different levels of involvement and permissions, they can perform [repository management tasks](./management-tasks.md) and together we [manage the FastAPI repository](./management.md).
diff --git a/docs/en/docs/features.md b/docs/en/docs/features.md index a1a271d28..b4cafd00a 100644 --- a/docs/en/docs/features.md +++ b/docs/en/docs/features.md @@ -73,11 +73,11 @@ Pass the keys and values of the `second_user_data` dict directly as key-value ar ### Editor support { #editor-support } -All the framework was designed to be easy and intuitive to use, all the decisions were tested on multiple editors even before starting development, to ensure the best development experience. +The whole framework was designed to be easy and intuitive to use, all the decisions were tested on multiple editors even before starting development, to ensure the best development experience. In the Python developer surveys, it's clear [that one of the most used features is "autocompletion"](https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features). -The whole **FastAPI** framework is based to satisfy that. Autocompletion works everywhere. +The whole **FastAPI** framework is designed to satisfy that. Autocompletion works everywhere. You will rarely need to come back to the docs. @@ -147,7 +147,7 @@ FastAPI includes an extremely easy to use, but extremely powerful ORMs, ODMs for databases. +Including external libraries also based on Pydantic, such as ORMs and ODMs for databases. This also means that in many cases you can pass the same object you get from a request **directly to the database**, as everything is validated automatically. diff --git a/docs/en/docs/help-fastapi.md b/docs/en/docs/help-fastapi.md index 3fcd400e7..14bd05646 100644 --- a/docs/en/docs/help-fastapi.md +++ b/docs/en/docs/help-fastapi.md @@ -26,7 +26,7 @@ You can follow **FastAPI** online in several places: You can "star" FastAPI in GitHub (clicking the star button at the top right): [https://github.com/fastapi/fastapi](https://github.com/fastapi/fastapi). ⭐️ -By adding a star, other users will be able to find it more easily and see that it has been already useful for others. +By adding a star, other users will be able to find it more easily and see that it has already been useful for others. ## Watch the GitHub repository for releases { #watch-the-github-repository-for-releases } diff --git a/docs/en/docs/how-to/configure-swagger-ui.md b/docs/en/docs/how-to/configure-swagger-ui.md index 7c3d9cb25..c7cacd97e 100644 --- a/docs/en/docs/how-to/configure-swagger-ui.md +++ b/docs/en/docs/how-to/configure-swagger-ui.md @@ -67,4 +67,4 @@ presets: [ These are **JavaScript** objects, not strings, so you can't pass them from Python code directly. -If you need to use JavaScript-only configurations like those, you can use one of the methods above. Override all the Swagger UI *path operation* and manually write any JavaScript you need. +If you need to use JavaScript-only configurations like those, you can use one of the methods above. Override the whole Swagger UI *path operation* and manually write any JavaScript you need. diff --git a/docs/en/docs/how-to/custom-request-and-route.md b/docs/en/docs/how-to/custom-request-and-route.md index bce232017..2b353d9b4 100644 --- a/docs/en/docs/how-to/custom-request-and-route.md +++ b/docs/en/docs/how-to/custom-request-and-route.md @@ -94,7 +94,7 @@ All we need to do is handle the request inside a `try`/`except` block: {* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[14,16] *} -If an exception occurs, the`Request` instance will still be in scope, so we can read and make use of the request body when handling the error: +If an exception occurs, the `Request` instance will still be in scope, so we can read and make use of the request body when handling the error: {* ../../docs_src/custom_request_and_route/tutorial002_an_py310.py hl[17:19] *} diff --git a/docs/en/docs/how-to/graphql.md b/docs/en/docs/how-to/graphql.md index 2d93876f3..de149a74a 100644 --- a/docs/en/docs/how-to/graphql.md +++ b/docs/en/docs/how-to/graphql.md @@ -57,4 +57,4 @@ If you need GraphQL, I still would recommend you check out [Strawberry](https:// You can learn more about **GraphQL** in the [official GraphQL documentation](https://graphql.org/). -You can also read more about each those libraries described above in their links. +You can also read more about each of those libraries described above in their links. diff --git a/docs/en/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md b/docs/en/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md index 99d3835c3..56a99f6a4 100644 --- a/docs/en/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md +++ b/docs/en/docs/how-to/migrate-from-pydantic-v1-to-pydantic-v2.md @@ -130,6 +130,6 @@ First try with `bump-pydantic`, if your tests pass and that works, then you're d If `bump-pydantic` doesn't work for your use case, you can use the support for both Pydantic v1 and v2 models in the same app to do the migration to Pydantic v2 gradually. -You could fist upgrade Pydantic to use the latest version 2, and change the imports to use `pydantic.v1` for all your models. +You could first upgrade Pydantic to use the latest version 2, and change the imports to use `pydantic.v1` for all your models. Then, you can start migrating your models from Pydantic v1 to v2 in groups, in gradual steps. 🚢 diff --git a/docs/en/docs/how-to/separate-openapi-schemas.md b/docs/en/docs/how-to/separate-openapi-schemas.md index 4eb684dc9..66755f8b7 100644 --- a/docs/en/docs/how-to/separate-openapi-schemas.md +++ b/docs/en/docs/how-to/separate-openapi-schemas.md @@ -46,7 +46,7 @@ If you interact with the docs and check the response, even though the code didn' This means that it will **always have a value**, it's just that sometimes the value could be `None` (or `null` in JSON). -That means that, clients using your API don't have to check if the value exists or not, they can **assume the field will always be there**, but just that in some cases it will have the default value of `None`. +That means that clients using your API don't have to check if the value exists or not, they can **assume the field will always be there**, but just that in some cases it will have the default value of `None`. The way to describe this in OpenAPI, is to mark that field as **required**, because it will always be there. diff --git a/docs/en/docs/index.md b/docs/en/docs/index.md index 0aeee755e..f4874520c 100644 --- a/docs/en/docs/index.md +++ b/docs/en/docs/index.md @@ -477,13 +477,13 @@ For a more complete example including more features, see the Dependency Injection** system. * Security and authentication, including support for **OAuth2** with **JWT tokens** and **HTTP Basic** auth. * More advanced (but equally easy) techniques for declaring **deeply nested JSON models** (thanks to Pydantic). * **GraphQL** integration with [Strawberry](https://strawberry.rocks) and other libraries. -* Many extra features (thanks to Starlette) as: +* Many extra features (thanks to Starlette) such as: * **WebSockets** * extremely easy tests based on HTTPX and `pytest` * **CORS** diff --git a/docs/en/docs/project-generation.md b/docs/en/docs/project-generation.md index aa579af5e..ab6e87527 100644 --- a/docs/en/docs/project-generation.md +++ b/docs/en/docs/project-generation.md @@ -1,8 +1,8 @@ # Full Stack FastAPI Template { #full-stack-fastapi-template } -Templates, while typically come with a specific setup, are designed to be flexible and customizable. This allows you to modify and adapt them to your project's requirements, making them an excellent starting point. 🏁 +Templates, while they typically come with a specific setup, are designed to be flexible and customizable. This allows you to modify and adapt them to your project's requirements, making them an excellent starting point. 🏁 -You can use this template to get started, as it includes a lot of the initial set up, security, database and some API endpoints already done for you. +You can use this template to get started, as it includes a lot of the initial setup, security, database and some API endpoints already done for you. GitHub Repository: [Full Stack FastAPI Template](https://github.com/tiangolo/full-stack-fastapi-template) diff --git a/docs/en/docs/python-types.md b/docs/en/docs/python-types.md index 976129117..c8d9bf41c 100644 --- a/docs/en/docs/python-types.md +++ b/docs/en/docs/python-types.md @@ -2,7 +2,7 @@ Python has support for optional "type hints" (also called "type annotations"). -These **"type hints"** or annotations are a special syntax that allow declaring the type of a variable. +These **"type hints"** or annotations are a special syntax that allows declaring the type of a variable. By declaring types for your variables, editors and tools can give you better support. @@ -44,7 +44,7 @@ It's a very simple program. But now imagine that you were writing it from scratch. -At some point you would have started the definition of the function, you had the parameters ready... +At some point you start defining the function, and you have the parameters ready... But then you have to call "that method that converts the first letter to upper case". @@ -80,7 +80,7 @@ Those are the "type hints": {* ../../docs_src/python_types/tutorial002_py310.py hl[1] *} -That is not the same as declaring default values like would be with: +That is not the same as declaring default values like it would be with: ```Python first_name="john", last_name="doe" diff --git a/docs/en/docs/reference/status.md b/docs/en/docs/reference/status.md index 6e0e816d3..16af90e0f 100644 --- a/docs/en/docs/reference/status.md +++ b/docs/en/docs/reference/status.md @@ -16,7 +16,7 @@ For example: * 403: `status.HTTP_403_FORBIDDEN` * etc. -It can be convenient to quickly access HTTP (and WebSocket) status codes in your app, using autocompletion for the name without having to remember the integer status codes by memory. +It can be convenient to quickly access HTTP (and WebSocket) status codes in your app, using autocompletion for the name without having to memorize the integer status codes. Read more about it in the [FastAPI docs about Response Status Code](https://fastapi.tiangolo.com/tutorial/response-status-code/). diff --git a/docs/en/docs/reference/websockets.md b/docs/en/docs/reference/websockets.md index bd9f438be..b1158b387 100644 --- a/docs/en/docs/reference/websockets.md +++ b/docs/en/docs/reference/websockets.md @@ -50,7 +50,7 @@ When you want to define dependencies that should be compatible with both HTTP an Additional classes for handling WebSockets. -Provided directly by Starlette, but you can import it from `fastapi`: +Provided directly by Starlette, but you can import them from `fastapi`: ```python from fastapi.websockets import WebSocketDisconnect, WebSocketState @@ -60,7 +60,7 @@ from fastapi.websockets import WebSocketDisconnect, WebSocketState When a client disconnects, a `WebSocketDisconnect` exception is raised, you can catch it. -You can import it directly form `fastapi`: +You can import it directly from `fastapi`: ```python from fastapi import WebSocketDisconnect diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 1ab8e490c..d890ca132 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -295,7 +295,7 @@ hide: ### Features * ✨ Add support for streaming JSON Lines and binary data with `yield`. PR [#15022](https://github.com/fastapi/fastapi/pull/15022) by [@tiangolo](https://github.com/tiangolo). - * This also upgrades Starlette from `>=0.40.0` to `>=0.46.0`, as it's needed to properly unrwap and re-raise exceptions from exception groups. + * This also upgrades Starlette from `>=0.40.0` to `>=0.46.0`, as it's needed to properly unwrap and re-raise exceptions from exception groups. * New docs: [Stream JSON Lines](https://fastapi.tiangolo.com/tutorial/stream-json-lines/). * And new docs: [Stream Data](https://fastapi.tiangolo.com/advanced/stream-data/). @@ -3115,7 +3115,7 @@ def my_dep(): ### Security fixes -* ⬆️ Upgrade minimum version of `python-multipart` to `>=0.0.7` to fix a vulnerability when using form data with a ReDos attack. You can also simply upgrade `python-multipart`. +* ⬆️ Upgrade minimum version of `python-multipart` to `>=0.0.7` to fix a vulnerability when using form data with a ReDoS attack. You can also simply upgrade `python-multipart`. Read more in the [advisory: Content-Type Header ReDoS](https://github.com/tiangolo/fastapi/security/advisories/GHSA-qf9m-vfgh-m389). @@ -5766,7 +5766,7 @@ router = APIRouter(prefix="/users", dependencies=[Depends(some_dependency)]) Most of these settings are now supported in `APIRouter`, which normally lives closer to the related code, so it is recommended to use `APIRouter` when possible. -But `include_router` is still useful to, for example, adding options (like `dependencies`, `prefix`, and `tags`) when including a third party router, or a generic router that is shared between several projects. +But `include_router` is still useful to, for example, add options (like `dependencies`, `prefix`, and `tags`) when including a third party router, or a generic router that is shared between several projects. This PR allows setting the (mostly new) parameters (additionally to the already existing parameters): @@ -5956,7 +5956,7 @@ Note: all the previous parameters are still there, so it's still possible to dec * Fix typo in docs for query parameters. PR [#1832](https://github.com/tiangolo/fastapi/pull/1832) by [@ycd](https://github.com/ycd). * Add docs about [Async Tests](https://fastapi.tiangolo.com/advanced/async-tests/). PR [#1619](https://github.com/tiangolo/fastapi/pull/1619) by [@empicano](https://github.com/empicano). * Raise an exception when using form data (`Form`, `File`) without having `python-multipart` installed. - * Up to now the application would run, and raise an exception only when receiving a request with form data, the new behavior, raising early, will prevent from deploying applications with broken dependencies. + * Up to now the application would run, and raise an exception only when receiving a request with form data, the new behavior, raising early, will prevent deploying applications with broken dependencies. * It also detects if the correct package `python-multipart` is installed instead of the incorrect `multipart` (both importable as `multipart`). * PR [#1851](https://github.com/tiangolo/fastapi/pull/1851) based on original PR [#1627](https://github.com/tiangolo/fastapi/pull/1627) by [@chrisngyn](https://github.com/chrisngyn), [@YKo20010](https://github.com/YKo20010), [@kx-chen](https://github.com/kx-chen). * Re-enable Gitter releases bot. PR [#1831](https://github.com/tiangolo/fastapi/pull/1831). @@ -6512,7 +6512,7 @@ Note: all the previous parameters are still there, so it's still possible to dec * When declaring a `response_model` it is used directly to generate the response content, from whatever was returned from the *path operation function*. * Before this, the return content was first passed through `jsonable_encoder` to ensure it was a "jsonable" object, like a `dict`, instead of an arbitrary object with attributes (like an ORM model). That's why you should make sure to update your Pydantic models for objects with attributes to use `orm_mode = True`. * If you don't have a `response_model`, the return object will still be passed through `jsonable_encoder` first. - * When a `response_model` is declared, the same `response_model` type declaration won't be used as is, it will be "cloned" to create an new one (a cloned Pydantic `Field` with all the submodels cloned as well). + * When a `response_model` is declared, the same `response_model` type declaration won't be used as is, it will be "cloned" to create a new one (a cloned Pydantic `Field` with all the submodels cloned as well). * This avoids/fixes a potential security issue: as the returned object is passed directly to Pydantic, if the returned object was a subclass of the `response_model` (e.g. you return a `UserInDB` that inherits from `User` but contains extra fields, like `hashed_password`, and `User` is used in the `response_model`), it would still pass the validation (because `UserInDB` is a subclass of `User`) and the object would be returned as-is, including the `hashed_password`. To fix this, the declared `response_model` is cloned, if it is a Pydantic model class (or contains Pydantic model classes in it, e.g. in a `List[Item]`), the Pydantic model class(es) will be a different one (the "cloned" one). So, an object that is a subclass won't simply pass the validation and returned as-is, because it is no longer a sub-class of the cloned `response_model`. Instead, a new Pydantic model object will be created with the contents of the returned object. So, it will be a new object (made with the data from the returned one), and will be filtered by the cloned `response_model`, containing only the declared fields as normally. * PR [#322](https://github.com/tiangolo/fastapi/pull/322). diff --git a/docs/en/docs/translations.md b/docs/en/docs/translations.md index ee5531877..c05b04ed7 100644 --- a/docs/en/docs/translations.md +++ b/docs/en/docs/translations.md @@ -19,7 +19,7 @@ Let's say that you want to request translations for a language that is not yet t * The first step would be for you to find other 2 people that would be willing to be reviewing translation PRs for that language with you. * Once there are at least 3 people that would be willing to commit to help maintain that language, you can continue the next steps. * Create a new discussion following the template. -* Tag the other 2 people that will help with the language, and ask them to confirm there they will help. +* Tag the other 2 people that will help with the language, and ask them to confirm in the comments that they will help. Once there are several people in the discussion, the FastAPI team can evaluate it and can make it an official translation. diff --git a/docs/en/docs/tutorial/bigger-applications.md b/docs/en/docs/tutorial/bigger-applications.md index 8950d59b4..25a314bec 100644 --- a/docs/en/docs/tutorial/bigger-applications.md +++ b/docs/en/docs/tutorial/bigger-applications.md @@ -232,7 +232,7 @@ would mean: But that file doesn't exist, our dependencies are in a file at `app/dependencies.py`. -Remember how our app/file structure looks like: +Remember what our app/file structure looks like: diff --git a/docs/en/docs/tutorial/body-nested-models.md b/docs/en/docs/tutorial/body-nested-models.md index 5479ab2a4..61ed93202 100644 --- a/docs/en/docs/tutorial/body-nested-models.md +++ b/docs/en/docs/tutorial/body-nested-models.md @@ -96,7 +96,7 @@ Again, doing just that declaration, with **FastAPI** you get: Apart from normal singular types like `str`, `int`, `float`, etc. you can use more complex singular types that inherit from `str`. -To see all the options you have, checkout [Pydantic's Type Overview](https://docs.pydantic.dev/latest/concepts/types/). You will see some examples in the next chapter. +To see all the options you have, check out [Pydantic's Type Overview](https://docs.pydantic.dev/latest/concepts/types/). You will see some examples in the next chapter. For example, as in the `Image` model we have a `url` field, we can declare it to be an instance of Pydantic's `HttpUrl` instead of a `str`: diff --git a/docs/en/docs/tutorial/debugging.md b/docs/en/docs/tutorial/debugging.md index 8db47b934..5b57fe85b 100644 --- a/docs/en/docs/tutorial/debugging.md +++ b/docs/en/docs/tutorial/debugging.md @@ -99,7 +99,7 @@ Here's how it might look: --- -If you use Pycharm, you can: +If you use PyCharm, you can: * Open the "Run" menu. * Select the option "Debug...". diff --git a/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md index 658dee7c2..5574af519 100644 --- a/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md @@ -234,6 +234,7 @@ participant operation as Path Operation Dependencies with `yield` have evolved over time to cover different use cases and fix some issues. If you want to see what has changed in different versions of FastAPI, you can read more about it in the advanced guide, in [Advanced Dependencies - Dependencies with `yield`, `HTTPException`, `except` and Background Tasks](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks). + ## Context Managers { #context-managers } ### What are "Context Managers" { #what-are-context-managers } diff --git a/docs/en/docs/tutorial/extra-data-types.md b/docs/en/docs/tutorial/extra-data-types.md index 611aa9b9e..63c914efe 100644 --- a/docs/en/docs/tutorial/extra-data-types.md +++ b/docs/en/docs/tutorial/extra-data-types.md @@ -36,7 +36,7 @@ Here are some of the additional data types you can use: * `datetime.timedelta`: * A Python `datetime.timedelta`. * In requests and responses will be represented as a `float` of total seconds. - * Pydantic also allows representing it as a "ISO 8601 time diff encoding", [see the docs for more info](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers). + * Pydantic also allows representing it as an "ISO 8601 time diff encoding", [see the docs for more info](https://docs.pydantic.dev/latest/concepts/serialization/#custom-serializers). * `frozenset`: * In requests and responses, treated the same as a `set`: * In requests, a list will be read, eliminating duplicates and converting it to a `set`. diff --git a/docs/en/docs/tutorial/extra-models.md b/docs/en/docs/tutorial/extra-models.md index e231aea90..d2b53cb66 100644 --- a/docs/en/docs/tutorial/extra-models.md +++ b/docs/en/docs/tutorial/extra-models.md @@ -18,7 +18,7 @@ If you don't know, you will learn what a "password hash" is in the [security cha ## Multiple models { #multiple-models } -Here's a general idea of how the models could look like with their password fields and the places where they are used: +Here's a general idea of what the models could look like with their password fields and the places where they are used: {* ../../docs_src/extra_models/tutorial001_py310.py hl[7,9,14,20,22,27:28,31:33,38:39] *} @@ -142,7 +142,7 @@ The supporting additional functions `fake_password_hasher` and `fake_save_user` Reducing code duplication is one of the core ideas in **FastAPI**. -As code duplication increments the chances of bugs, security issues, code desynchronization issues (when you update in one place but not in the others), etc. +As code duplication increases the chances of bugs, security issues, code desynchronization issues (when you update in one place but not in the others), etc. And these models are all sharing a lot of the data and duplicating attribute names and types. @@ -208,4 +208,4 @@ In this case, you can use `dict`: Use multiple Pydantic models and inherit freely for each case. -You don't need to have a single data model per entity if that entity must be able to have different "states". As the case with the user "entity" with a state including `password`, `password_hash` and no password. +You don't need to have a single data model per entity if that entity must be able to have different "states". The **user** "entity" is an example, with states that include `password`, `password_hash`, or no password. diff --git a/docs/en/docs/tutorial/first-steps.md b/docs/en/docs/tutorial/first-steps.md index ae43e401b..a2020002c 100644 --- a/docs/en/docs/tutorial/first-steps.md +++ b/docs/en/docs/tutorial/first-steps.md @@ -108,7 +108,7 @@ OpenAPI defines an API schema for your API. And that schema includes definitions #### Check the `openapi.json` { #check-the-openapi-json } -If you are curious about how the raw OpenAPI schema looks like, FastAPI automatically generates a JSON (schema) with the descriptions of all your API. +If you are curious about what the raw OpenAPI schema looks like, FastAPI automatically generates a JSON (schema) with the descriptions of all your API. You can see it directly at: [http://127.0.0.1:8000/openapi.json](http://127.0.0.1:8000/openapi.json). diff --git a/docs/en/docs/tutorial/handling-errors.md b/docs/en/docs/tutorial/handling-errors.md index 78a5f1f20..bb99813be 100644 --- a/docs/en/docs/tutorial/handling-errors.md +++ b/docs/en/docs/tutorial/handling-errors.md @@ -1,6 +1,6 @@ # Handling Errors { #handling-errors } -There are many situations in which you need to notify an error to a client that is using your API. +There are many situations in which you need to report an error to a client that is using your API. This client could be a browser with a frontend, a code from someone else, an IoT device, etc. @@ -71,7 +71,7 @@ They are handled automatically by **FastAPI** and converted to JSON. ## Add custom headers { #add-custom-headers } -There are some situations in where it's useful to be able to add custom headers to the HTTP error. For example, for some types of security. +There are some situations where it's useful to be able to add custom headers to the HTTP error. For example, for some types of security. You probably won't need to use it directly in your code. diff --git a/docs/en/docs/tutorial/index.md b/docs/en/docs/tutorial/index.md index 8a37756c7..9e7357919 100644 --- a/docs/en/docs/tutorial/index.md +++ b/docs/en/docs/tutorial/index.md @@ -92,7 +92,7 @@ FastAPI has an [official extension for VS Code](https://marketplace.visualstudio ## Advanced User Guide { #advanced-user-guide } -There is also an **Advanced User Guide** that you can read later after this **Tutorial - User guide**. +There is also an **Advanced User Guide** that you can read later after this **Tutorial - User Guide**. The **Advanced User Guide** builds on this one, uses the same concepts, and teaches you some extra features. diff --git a/docs/en/docs/tutorial/path-operation-configuration.md b/docs/en/docs/tutorial/path-operation-configuration.md index 8dfc6e2ff..103d7a4f2 100644 --- a/docs/en/docs/tutorial/path-operation-configuration.md +++ b/docs/en/docs/tutorial/path-operation-configuration.md @@ -98,7 +98,7 @@ It will be clearly marked as deprecated in the interactive docs: -Check how deprecated and non-deprecated *path operations* look like: +Check what deprecated and non-deprecated *path operations* look like: diff --git a/docs/en/docs/tutorial/query-params-str-validations.md b/docs/en/docs/tutorial/query-params-str-validations.md index 0714d8beb..eb9fa2607 100644 --- a/docs/en/docs/tutorial/query-params-str-validations.md +++ b/docs/en/docs/tutorial/query-params-str-validations.md @@ -406,7 +406,7 @@ But if you're curious about this specific code example and you're still entertai #### String with `value.startswith()` { #string-with-value-startswith } -Did you notice? a string using `value.startswith()` can take a tuple, and it will check each value in the tuple: +Did you notice? A string using `value.startswith()` can take a tuple, and it will check each value in the tuple: {* ../../docs_src/query_params_str_validations/tutorial015_an_py310.py ln[16:19] hl[17] *} diff --git a/docs/en/docs/tutorial/query-params.md b/docs/en/docs/tutorial/query-params.md index 563d39f7d..cb89e23e7 100644 --- a/docs/en/docs/tutorial/query-params.md +++ b/docs/en/docs/tutorial/query-params.md @@ -21,7 +21,7 @@ As they are part of the URL, they are "naturally" strings. But when you declare them with Python types (in the example above, as `int`), they are converted to that type and validated against it. -All the same process that applied for path parameters also applies for query parameters: +All the same processes that apply to path parameters also apply to query parameters: * Editor support (obviously) * Data "parsing" diff --git a/docs/en/docs/tutorial/request-files.md b/docs/en/docs/tutorial/request-files.md index fe4290449..df7894781 100644 --- a/docs/en/docs/tutorial/request-files.md +++ b/docs/en/docs/tutorial/request-files.md @@ -60,7 +60,7 @@ Using `UploadFile` has several advantages over `bytes`: * You don't have to use `File()` in the default value of the parameter. * It uses a "spooled" file: - * A file stored in memory up to a maximum size limit, and after passing this limit it will be stored in disk. + * A file stored in memory up to a maximum size limit, and after passing this limit it will be stored on disk. * This means that it will work well for large files like images, videos, large binaries, etc. without consuming all the memory. * You can get metadata from the uploaded file. * It has a [file-like](https://docs.python.org/3/glossary.html#term-file-like-object) `async` interface. @@ -111,7 +111,7 @@ When you use the `async` methods, **FastAPI** runs the file methods in a threadp ## What is "Form Data" { #what-is-form-data } -The way HTML forms (`
`) sends the data to the server normally uses a "special" encoding for that data, it's different from JSON. +The way HTML forms (`
`) send the data to the server normally uses a "special" encoding for that data, it's different from JSON. **FastAPI** will make sure to read that data from the right place instead of JSON. diff --git a/docs/en/docs/tutorial/request-forms.md b/docs/en/docs/tutorial/request-forms.md index 64e90a244..45af663c8 100644 --- a/docs/en/docs/tutorial/request-forms.md +++ b/docs/en/docs/tutorial/request-forms.md @@ -46,7 +46,7 @@ To declare form bodies, you need to use `Form` explicitly, because without it th ## About "Form Fields" { #about-form-fields } -The way HTML forms (`
`) sends the data to the server normally uses a "special" encoding for that data, it's different from JSON. +The way HTML forms (`
`) send the data to the server normally uses a "special" encoding for that data, it's different from JSON. **FastAPI** will make sure to read that data from the right place instead of JSON. diff --git a/docs/en/docs/tutorial/schema-extra-example.md b/docs/en/docs/tutorial/schema-extra-example.md index 67c7ac37c..280162531 100644 --- a/docs/en/docs/tutorial/schema-extra-example.md +++ b/docs/en/docs/tutorial/schema-extra-example.md @@ -78,7 +78,7 @@ Nevertheless, at the time of writing this, Swagger ### OpenAPI-specific `examples` { #openapi-specific-examples } -Since before **JSON Schema** supported `examples` OpenAPI had support for a different field also called `examples`. +Since before **JSON Schema** supported `examples`, OpenAPI had support for a different field also called `examples`. This **OpenAPI-specific** `examples` goes in another section in the OpenAPI specification. It goes in the **details for each *path operation***, not inside each JSON Schema. diff --git a/docs/en/docs/tutorial/security/first-steps.md b/docs/en/docs/tutorial/security/first-steps.md index 095b8b901..7dae3edf4 100644 --- a/docs/en/docs/tutorial/security/first-steps.md +++ b/docs/en/docs/tutorial/security/first-steps.md @@ -88,7 +88,7 @@ And it can also be used by yourself, to debug, check and test the same applicati ## The `password` flow { #the-password-flow } -Now let's go back a bit and understand what is all that. +Now let's go back a bit and understand what all that is. The `password` "flow" is one of the ways ("flows") defined in OAuth2, to handle security and authentication. diff --git a/docs/en/docs/tutorial/security/oauth2-jwt.md b/docs/en/docs/tutorial/security/oauth2-jwt.md index 6c1ab27b2..68bad4e10 100644 --- a/docs/en/docs/tutorial/security/oauth2-jwt.md +++ b/docs/en/docs/tutorial/security/oauth2-jwt.md @@ -124,7 +124,7 @@ This ensures the endpoint takes roughly the same amount of time to respond wheth /// note -If you check the new (fake) database `fake_users_db`, you will see how the hashed password looks like now: `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`. +If you check the new (fake) database `fake_users_db`, you will see what the hashed password looks like now: `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`. /// diff --git a/docs/en/docs/tutorial/security/simple-oauth2.md b/docs/en/docs/tutorial/security/simple-oauth2.md index afe3ba128..e482cea13 100644 --- a/docs/en/docs/tutorial/security/simple-oauth2.md +++ b/docs/en/docs/tutorial/security/simple-oauth2.md @@ -6,7 +6,7 @@ Now let's build from the previous chapter and add the missing parts to have a co We are going to use **FastAPI** security utilities to get the `username` and `password`. -OAuth2 specifies that when using the "password flow" (that we are using) the client/user must send a `username` and `password` fields as form data. +OAuth2 specifies that when using the "password flow" (that we are using) the client/user must send `username` and `password` fields as form data. And the spec says that the fields have to be named like that. So `user-name` or `email` wouldn't work. @@ -190,7 +190,7 @@ We want to get the `current_user` *only* if this user is active. So, we create an additional dependency `get_current_active_user` that in turn uses `get_current_user` as a dependency. -Both of these dependencies will just return an HTTP error if the user doesn't exist, or if is inactive. +Both of these dependencies will just return an HTTP error if the user doesn't exist, or is inactive. So, in our endpoint, we will only get a user if the user exists, was correctly authenticated, and is active: diff --git a/docs/en/docs/tutorial/sql-databases.md b/docs/en/docs/tutorial/sql-databases.md index b8cbac295..1f4b12ca9 100644 --- a/docs/en/docs/tutorial/sql-databases.md +++ b/docs/en/docs/tutorial/sql-databases.md @@ -201,7 +201,7 @@ Then let's create `Hero`, the actual *table model*, with the **extra fields** th * `id` * `secret_name` -Because `Hero` inherits form `HeroBase`, it **also** has the **fields** declared in `HeroBase`, so all the fields for `Hero` are: +Because `Hero` inherits from `HeroBase`, it **also** has the **fields** declared in `HeroBase`, so all the fields for `Hero` are: * `id` * `name` diff --git a/docs/en/docs/tutorial/static-files.md b/docs/en/docs/tutorial/static-files.md index 38c2ef248..0b73a35c1 100644 --- a/docs/en/docs/tutorial/static-files.md +++ b/docs/en/docs/tutorial/static-files.md @@ -33,7 +33,7 @@ The `directory="static"` refers to the name of the directory that contains your The `name="static"` gives it a name that can be used internally by **FastAPI**. -All these parameters can be different than "`static`", adjust them with the needs and specific details of your own application. +All these parameters can be different than "`static`", adjust them to the needs and specific details of your own application. ## More info { #more-info } diff --git a/docs/en/docs/tutorial/testing.md b/docs/en/docs/tutorial/testing.md index 72f849f4b..38976dc31 100644 --- a/docs/en/docs/tutorial/testing.md +++ b/docs/en/docs/tutorial/testing.md @@ -24,7 +24,7 @@ Import `TestClient`. Create a `TestClient` by passing your **FastAPI** application to it. -Create functions with a name that starts with `test_` (this is standard `pytest` conventions). +Create functions with a name that starts with `test_` (this is a standard `pytest` convention). Use the `TestClient` object the same way as you do with `httpx`. diff --git a/docs/en/docs/virtual-environments.md b/docs/en/docs/virtual-environments.md index 119a6926a..7f95cad24 100644 --- a/docs/en/docs/virtual-environments.md +++ b/docs/en/docs/virtual-environments.md @@ -100,7 +100,7 @@ $ uv venv By default, `uv` will create a virtual environment in a directory called `.venv`. -But you could customize it passing an additional argument with the directory name. +But you could customize it by passing an additional argument with the directory name. /// @@ -258,7 +258,7 @@ $ python -m ensurepip --upgrade
-This command will install pip if it is not already installed and also ensures that the installed version of pip is at least as recent as the one available in `ensurepip`. +This command will install pip if it is not already installed and also ensure that the installed version of pip is at least as recent as the one available in `ensurepip`. /// @@ -447,7 +447,7 @@ Now you're ready to start working on your project. /// tip -Do you want to understand what's all that above? +Do you want to understand what all that above is? Continue reading. πŸ‘‡πŸ€“ @@ -548,7 +548,7 @@ Also, depending on your operating system (e.g. Linux, Windows, macOS), it could ## Where are Packages Installed { #where-are-packages-installed } -When you install Python, it creates some directories with some files in your computer. +When you install Python, it creates some directories with some files on your computer. Some of these directories are the ones in charge of having all the packages you install. @@ -568,7 +568,7 @@ That will download a compressed file with the FastAPI code, normally from [PyPI] It will also **download** files for other packages that FastAPI depends on. -Then it will **extract** all those files and put them in a directory in your computer. +Then it will **extract** all those files and put them in a directory on your computer. By default, it will put those files downloaded and extracted in the directory that comes with your Python installation, that's the **global environment**. @@ -846,7 +846,7 @@ This is a simple guide to get you started and teach you how everything works **u There are many **alternatives** to managing virtual environments, package dependencies (requirements), projects. -Once you are ready and want to use a tool to **manage the entire project**, packages dependencies, virtual environments, etc. I would suggest you try [uv](https://github.com/astral-sh/uv). +Once you are ready and want to use a tool to **manage the entire project**, package dependencies, virtual environments, etc. I would suggest you try [uv](https://github.com/astral-sh/uv). `uv` can do a lot of things, it can: