📝 Move tutorial src files to top level docs

This commit is contained in:
Sebastián Ramírez
2018-12-21 16:22:33 +04:00
parent d5e782074f
commit 0a65c41909
132 changed files with 134 additions and 422 deletions

View File

@@ -1,13 +1,13 @@
Coming soon...
```Python
{!./tutorial/src/application-configuration/tutorial001.py!}
{!./src/application-configuration/tutorial001.py!}
```
```Python
{!./tutorial/src/application-configuration/tutorial002.py!}
{!./src/application-configuration/tutorial002.py!}
```
```Python
{!./tutorial/src/application-configuration/tutorial003.py!}
{!./src/application-configuration/tutorial003.py!}
```

View File

@@ -1,13 +1,13 @@
Coming soon...
```Python
{!./tutorial/src/bigger_applications/app/routers/tutorial001.py!}
{!./src/bigger_applications/app/routers/tutorial001.py!}
```
```Python
{!./tutorial/src/bigger_applications/app/routers/tutorial002.py!}
{!./src/bigger_applications/app/routers/tutorial002.py!}
```
```Python
{!./tutorial/src/bigger_applications/app/tutorial003.py!}
{!./src/bigger_applications/app/tutorial003.py!}
```

View File

@@ -7,7 +7,7 @@ First, of course, you can mix `Path`, `Query` and request body parameter declara
And you can also declare body parameters as optional, by setting the default to `None`:
```Python hl_lines="17 18 19"
{!./tutorial/src/body_multiple_params/tutorial001.py!}
{!./src/body_multiple_params/tutorial001.py!}
```
!!! note
@@ -30,7 +30,7 @@ In the previous example, the path operations would expect a JSON body with the a
But you can also declare multiple body parameters, e.g. `item` and `user`:
```Python hl_lines="20"
{!./tutorial/src/body_multiple_params/tutorial002.py!}
{!./src/body_multiple_params/tutorial002.py!}
```
In this case, **FastAPI** will notice that there are more than one body parameter in the function (two parameters that are Pydantic models).
@@ -72,7 +72,7 @@ But you can instruct **FastAPI** to treat it as another body key using `Body`:
```Python hl_lines="21"
{!./tutorial/src/body_multiple_params/tutorial003.py!}
{!./src/body_multiple_params/tutorial003.py!}
```
In this case, **FastAPI** will expect a body like:
@@ -109,7 +109,7 @@ q: str = None
as in:
```Python hl_lines="25"
{!./tutorial/src/body_multiple_params/tutorial004.py!}
{!./src/body_multiple_params/tutorial004.py!}
```
!!! info
@@ -131,7 +131,7 @@ item: Item = Body(..., embed=True)
as in:
```Python hl_lines="15"
{!./tutorial/src/body_multiple_params/tutorial005.py!}
{!./src/body_multiple_params/tutorial005.py!}
```
In this case **FastAPI** will expect a body like:

View File

@@ -5,7 +5,7 @@ With **FastAPI**, you can define, validate, document, and use arbitrarily deeply
You can define an attribute to be a subtype. For example, a Python `list`:
```Python hl_lines="12"
{!./tutorial/src/body_nested_models/tutorial001.py!}
{!./src/body_nested_models/tutorial001.py!}
```
This will make `tags` be a list of items. Although it doesn't declare the type of each of the items.
@@ -19,7 +19,7 @@ But Python has a specific way to declare lists with subtypes:
First, import `List` from standard Python's `typing` module:
```Python hl_lines="1"
{!./tutorial/src/body_nested_models/tutorial002.py!}
{!./src/body_nested_models/tutorial002.py!}
```
### Declare a `List` with a subtype
@@ -42,7 +42,7 @@ Use that same standard syntax for model attributes with subtypes.
So, in our example, we can make `tags` be specifically a "list of strings":
```Python hl_lines="14"
{!./tutorial/src/body_nested_models/tutorial002.py!}
{!./src/body_nested_models/tutorial002.py!}
```
## Set types
@@ -54,7 +54,7 @@ And Python has a special data type for sets of unique items, the `set`.
Then we can import `Set` and declare `tags` as a `set` of `str`:
```Python hl_lines="1 14"
{!./tutorial/src/body_nested_models/tutorial003.py!}
{!./src/body_nested_models/tutorial003.py!}
```
With this, even if you receive a request with duplicate data, it will be converted to a set of unique items.
@@ -78,7 +78,7 @@ All that, arbitrarily nested.
For example, we can define an `Image` model:
```Python hl_lines="9 10 11"
{!./tutorial/src/body_nested_models/tutorial004.py!}
{!./src/body_nested_models/tutorial004.py!}
```
### Use the submodel as a type
@@ -86,7 +86,7 @@ For example, we can define an `Image` model:
And then we can use it as the type of an attribute:
```Python hl_lines="20"
{!./tutorial/src/body_nested_models/tutorial004.py!}
{!./src/body_nested_models/tutorial004.py!}
```
This would mean that **FastAPI** would expect a body similar to:
@@ -121,7 +121,7 @@ To see all the options you have, checkout the docs for <a href="https://pydantic
For example, as in the `Image` model we have a `url` field, we can declare it to be instead of a `str`, a Pydantic's `UrlStr`:
```Python hl_lines="5 11"
{!./tutorial/src/body_nested_models/tutorial005.py!}
{!./src/body_nested_models/tutorial005.py!}
```
The string will be checked to be a valid URL, and documented in JSON Schema / OpenAPI as such.
@@ -131,7 +131,7 @@ The string will be checked to be a valid URL, and documented in JSON Schema / Op
You can also use Pydantic models as subtypes of `list`, `set`, etc:
```Python hl_lines="21"
{!./tutorial/src/body_nested_models/tutorial006.py!}
{!./src/body_nested_models/tutorial006.py!}
```
This will expect (convert, validate, document, etc) a JSON body like:
@@ -168,7 +168,7 @@ This will expect (convert, validate, document, etc) a JSON body like:
You can define arbitrarily deeply nested models:
```Python hl_lines="10 15 21 24 28"
{!./tutorial/src/body_nested_models/tutorial007.py!}
{!./src/body_nested_models/tutorial007.py!}
```
!!! info
@@ -185,7 +185,7 @@ images: List[Image]
as in:
```Python hl_lines="16"
{!./tutorial/src/body_nested_models/tutorial008.py!}
{!./src/body_nested_models/tutorial008.py!}
```
## Editor support everywhere

View File

@@ -5,7 +5,7 @@ The same way you can declare additional validation and metadata in path operatio
First, you have to import it:
```Python hl_lines="2"
{!./tutorial/src/body_schema/tutorial001.py!}
{!./src/body_schema/tutorial001.py!}
```
!!! warning
@@ -17,7 +17,7 @@ First, you have to import it:
You can then use `Schema` with model attributes:
```Python hl_lines="9 10"
{!./tutorial/src/body_schema/tutorial001.py!}
{!./src/body_schema/tutorial001.py!}
```
`Schema` works the same way as `Query`, `Path` and `Body`, it has all the same parameters, etc.
@@ -45,7 +45,7 @@ If you know JSON Schema and want to add extra information appart from what we ha
For example, you can use that functionality to pass a <a href="http://json-schema.org/latest/json-schema-validation.html#rfc.section.8.5" target="_blank">JSON Schema example</a> field to a body request JSON Schema:
```Python hl_lines="20 21 22 23 24 25"
{!./tutorial/src/body_schema/tutorial002.py!}
{!./src/body_schema/tutorial002.py!}
```
## Recap

View File

@@ -5,7 +5,7 @@ To declare a request body, you use <a href="https://pydantic-docs.helpmanual.io/
First, you need to import `BaseModel` from `pydantic`:
```Python hl_lines="2"
{!./tutorial/src/body/tutorial001.py!}
{!./src/body/tutorial001.py!}
```
## Create your data model
@@ -15,7 +15,7 @@ Then you declare your data model as a class that inherits from `BaseModel`.
Use standard Python types for all the attributes:
```Python hl_lines="5 6 7 8 9"
{!./tutorial/src/body/tutorial001.py!}
{!./src/body/tutorial001.py!}
```
The same as when declaring query parameters, when a model attribute has a default value, it is not required. Otherwise, it is required. Use `None` to make it just optional.
@@ -45,7 +45,7 @@ For example, this model above declares a JSON "`object`" (or Python `dict`) like
To add it to your path operation, declare it the same way you declared path and query parameters:
```Python hl_lines="16"
{!./tutorial/src/body/tutorial001.py!}
{!./src/body/tutorial001.py!}
```
...and declare its type as the model you created, `Item`.
@@ -101,7 +101,7 @@ But you would get the same editor support with <a href="https://www.jetbrains.co
Inside of the function, you can access all the attributes of the model object directly:
```Python hl_lines="19"
{!./tutorial/src/body/tutorial002.py!}
{!./src/body/tutorial002.py!}
```
## Request body + path parameters
@@ -111,7 +111,7 @@ You can declare path parameters and body requests at the same time.
**FastAPI** will recognize that the function parameters that match path parameters should be **taken from the path**, and that function parameters that are declared to be Pydantic models should be **taken from the request body**.
```Python hl_lines="15 16"
{!./tutorial/src/body/tutorial003.py!}
{!./src/body/tutorial003.py!}
```
## Request body + path + query parameters
@@ -121,7 +121,7 @@ You can also declare **body**, **path** and **query** parameters, all at the sam
**FastAPI** will recognize each of them and take the data from the correct place.
```Python hl_lines="16"
{!./tutorial/src/body/tutorial004.py!}
{!./src/body/tutorial004.py!}
```
The function parameters will be recognized as follows:

View File

@@ -5,7 +5,7 @@ You can define Cookie parameters the same way you define `Query` and `Path` para
First import `Cookie`:
```Python hl_lines="1"
{!./tutorial/src/cookie_params/tutorial001.py!}
{!./src/cookie_params/tutorial001.py!}
```
## Declare `Cookie` parameteres
@@ -15,7 +15,7 @@ Then declare the cookie parameters using the same structure as with `Path` and `
The first value is the default value, you can pass all the extra validation or annotation parameteres:
```Python hl_lines="7"
{!./tutorial/src/cookie_params/tutorial001.py!}
{!./src/cookie_params/tutorial001.py!}
```
!!! info

View File

@@ -14,7 +14,7 @@ For example, if you are squeezing performance, you can use `ujson` and set the r
### Import `UJSONResponse`
```Python hl_lines="2"
{!./tutorial/src/custom_response/tutorial001.py!}
{!./src/custom_response/tutorial001.py!}
```
!!! note
@@ -25,7 +25,7 @@ For example, if you are squeezing performance, you can use `ujson` and set the r
Make your path operation use `UJSONResponse` as the response class using the parameter `content_type`:
```Python hl_lines="7"
{!./tutorial/src/custom_response/tutorial001.py!}
{!./src/custom_response/tutorial001.py!}
```
!!! info
@@ -40,7 +40,7 @@ To return a response with HTML directly from **FastAPI**, use `HTMLResponse`.
### Import `HTMLResponse`
```Python hl_lines="2"
{!./tutorial/src/custom_response/tutorial002.py!}
{!./src/custom_response/tutorial002.py!}
```
!!! note
@@ -52,7 +52,7 @@ To return a response with HTML directly from **FastAPI**, use `HTMLResponse`.
Pass `HTMLResponse` as the parameter `content_type` of your path operation:
```Python hl_lines="7"
{!./tutorial/src/custom_response/tutorial002.py!}
{!./src/custom_response/tutorial002.py!}
```
!!! info
@@ -72,7 +72,7 @@ If you return an object that is an instance of Starlette's `Response`, it will b
The same example from above, returning an `HTMLResponse`, could look like:
```Python hl_lines="7"
{!./tutorial/src/custom_response/tutorial003.py!}
{!./src/custom_response/tutorial003.py!}
```
!!! info
@@ -93,7 +93,7 @@ The `content_type` class will then be used only to document the OpenAPI path ope
For example, it could be something like:
```Python hl_lines="7 23"
{!./tutorial/src/custom_response/tutorial004.py!}
{!./src/custom_response/tutorial004.py!}
```
In this example, the function `generate_html_response()` already generates a Starlette `Response` instead of the HTML in a `str`.
@@ -105,7 +105,7 @@ By returning the result of calling `generate_html_response()`, you are already r
But by declaring it also in the path operation decorator:
```Python hl_lines="21"
{!./tutorial/src/custom_response/tutorial004.py!}
{!./src/custom_response/tutorial004.py!}
```
#### OpenAPI knows how to document it

View File

@@ -13,7 +13,7 @@ Let's first focus on the dependency.
It is just a function that can take all the same parameters that a path operation function can take:
```Python hl_lines="6 7"
{!./tutorial/src/dependencies/tutorial001.py!}
{!./src/dependencies/tutorial001.py!}
```
That's it.
@@ -37,7 +37,7 @@ And then it just returns a `dict` containing those values.
## Import `Depends`
```Python hl_lines="1"
{!./tutorial/src/dependencies/tutorial001.py!}
{!./src/dependencies/tutorial001.py!}
```
## Declare the dependency, in the "dependant"
@@ -45,7 +45,7 @@ And then it just returns a `dict` containing those values.
The same way you use `Body`, `Query`, etc. with your path operation function parameters, use `Depends` with a new parameter:
```Python hl_lines="11"
{!./tutorial/src/dependencies/tutorial001.py!}
{!./src/dependencies/tutorial001.py!}
```
Although you use it in the parameters of your function too, `Depends` works a bit differently.

View File

@@ -5,7 +5,7 @@ Before diving deeper into the **Dependency Injection** system, let's upgrade the
In the previous example, we where returning a `dict` from our dependency ("dependable"):
```Python hl_lines="7"
{!./tutorial/src/dependencies/tutorial001.py!}
{!./src/dependencies/tutorial001.py!}
```
But then we get a `dict` in the parameter `commons` of the path operation function.
@@ -21,7 +21,7 @@ Let's use them here too.
Create a model for the common parameters (and don't pay attention to the rest, for now):
```Python hl_lines="11 12 13 14"
{!./tutorial/src/dependencies/tutorial002.py!}
{!./src/dependencies/tutorial002.py!}
```
## Return a Pydantic model
@@ -29,7 +29,7 @@ Create a model for the common parameters (and don't pay attention to the rest, f
Now we can return a Pydantic model from the dependency ("dependable") with the same data as the dict before:
```Python hl_lines="18"
{!./tutorial/src/dependencies/tutorial002.py!}
{!./src/dependencies/tutorial002.py!}
```
## Declare the Pydantic model
@@ -43,7 +43,7 @@ commons: CommonQueryParams = Depends(common_parameters)
It won't be interpreted as a JSON request `Body` because we are using `Depends`:
```Python hl_lines="22"
{!./tutorial/src/dependencies/tutorial002.py!}
{!./src/dependencies/tutorial002.py!}
```
!!! info
@@ -56,7 +56,7 @@ It won't be interpreted as a JSON request `Body` because we are using `Depends`:
And now we can use that model in our code, with all the lovable editor support:
```Python hl_lines="24 25 26"
{!./tutorial/src/dependencies/tutorial002.py!}
{!./src/dependencies/tutorial002.py!}
```
<img src="/img/tutorial/dependencies/image02.png">

View File

@@ -14,7 +14,7 @@ This is especially the case for user models, because:
Here's a general idea of how the models could look like with their password fields and the places where they are used:
```Python hl_lines="8 10 15 21 23 32 34 39 40"
{!./tutorial/src/extra_models/tutorial001.py!}
{!./src/extra_models/tutorial001.py!}
```
!!! warning
@@ -37,7 +37,7 @@ All the data conversion, validation, documentation, etc. will still work as norm
That way, we can declare just the differences between the models (with plaintext `password`, with `hashed_password` and without password):
```Python hl_lines="8 14 15 18 19 22 23"
{!./tutorial/src/extra_models/tutorial002.py!}
{!./src/extra_models/tutorial002.py!}
```
## Recap

View File

@@ -1,7 +1,7 @@
The simplest FastAPI file could look like this:
```Python
{!tutorial/src/first_steps/tutorial001.py!}
{!./src/first_steps/tutorial001.py!}
```
Copy that to a file `main.py`.
@@ -89,7 +89,7 @@ It will show a JSON starting with something like:
### Step 1: import `FastAPI`
```Python hl_lines="1"
{!tutorial/src/first_steps/tutorial001.py!}
{!./src/first_steps/tutorial001.py!}
```
`FastAPI` is a Python class that provides all the functionality for your API.
@@ -102,7 +102,7 @@ It will show a JSON starting with something like:
### Step 2: create a `FastAPI` "instance"
```Python hl_lines="3"
{!tutorial/src/first_steps/tutorial001.py!}
{!./src/first_steps/tutorial001.py!}
```
Here the `app` variable will be an "instance" of the class `FastAPI`.
@@ -118,7 +118,7 @@ uvicorn main:app --debug
If you create your app like:
```Python hl_lines="3"
{!tutorial/src/first_steps/tutorial002.py!}
{!./src/first_steps/tutorial002.py!}
```
And put it in a file `main.py`, then you would call `uvicorn` like:
@@ -188,7 +188,7 @@ We are going to call them "operations" too.
#### Define a path operation function
```Python hl_lines="6"
{!tutorial/src/first_steps/tutorial001.py!}
{!./src/first_steps/tutorial001.py!}
```
The `@app.get("/")` tells **FastAPI** that the function right below is in charge of handling requests that go to:
@@ -221,7 +221,7 @@ And the more exotic ones:
### Step 4: define the path operation function
```Python hl_lines="7"
{!tutorial/src/first_steps/tutorial001.py!}
{!./src/first_steps/tutorial001.py!}
```
This is a Python function.
@@ -235,7 +235,7 @@ In this case, it is an `async` function.
You could also define it as a normal function instead of `async def`:
```Python hl_lines="7"
{!tutorial/src/first_steps/tutorial003.py!}
{!./src/first_steps/tutorial003.py!}
```
To know the difference, read the section about [Concurrency and `async` / `await`](/async/).
@@ -243,7 +243,7 @@ To know the difference, read the section about [Concurrency and `async` / `await
### Step 5: return the content
```Python hl_lines="8"
{!tutorial/src/first_steps/tutorial001.py!}
{!./src/first_steps/tutorial001.py!}
```
You can return a `dict`, `list`, singular values as `str`, `int`, etc.

View File

@@ -5,7 +5,7 @@ You can define Header parameters the same way you define `Query`, `Path` and `Co
First import `Header`:
```Python hl_lines="1"
{!./tutorial/src/header_params/tutorial001.py!}
{!./src/header_params/tutorial001.py!}
```
## Declare `Header` parameteres
@@ -15,7 +15,7 @@ Then declare the header parameters using the same structure as with `Path`, `Que
The first value is the default value, you can pass all the extra validation or annotation parameteres:
```Python hl_lines="7"
{!./tutorial/src/header_params/tutorial001.py!}
{!./src/header_params/tutorial001.py!}
```
!!! info
@@ -41,7 +41,7 @@ So, you can use `user_agent` as you normally would in Python code, instead of ne
If for some reason you need to disable automatic conversion of underscores to hyphens, set the parameter `convert_underscores` of `Header` to `False`:
```Python hl_lines="7"
{!./tutorial/src/header_params/tutorial002.py!}
{!./src/header_params/tutorial002.py!}
```
!!! warning

View File

@@ -15,7 +15,7 @@ You can adapt it to any other NoSQL database like:
For now, don't pay attention to the rest, only the imports:
```Python hl_lines="6 7 8"
{!./tutorial/src/nosql_databases/tutorial001.py!}
{!./src/nosql_databases/tutorial001.py!}
```
## Define a constant to use as a "document type"
@@ -25,7 +25,7 @@ We will use it later as a fixed field `type` in our documents.
This is not required by Couchbase, but is a good practice that will help you afterwards.
```Python hl_lines="10"
{!./tutorial/src/nosql_databases/tutorial001.py!}
{!./src/nosql_databases/tutorial001.py!}
```
## Add a function to get a `Bucket`
@@ -50,7 +50,7 @@ This utility function will:
* Return it.
```Python hl_lines="13 14 15 16 17 18 19 20"
{!./tutorial/src/nosql_databases/tutorial001.py!}
{!./src/nosql_databases/tutorial001.py!}
```
## Create Pydantic models
@@ -62,7 +62,7 @@ As **Couchbase** "documents" are actually just "JSON objects", we can model them
First, let's create a `User` model:
```Python hl_lines="23 24 25 26 27"
{!./tutorial/src/nosql_databases/tutorial001.py!}
{!./src/nosql_databases/tutorial001.py!}
```
We will use this model in our path operation function, so, we don't include in it the `hashed_password`.
@@ -76,7 +76,7 @@ This will have the data that is actually stored in the database.
We don't create it as a subclass of Pydantic's `BaseModel` but as a subclass of our own `User`, because it will have all the attributes in `User` plus a couple more:
```Python hl_lines="30 31 32"
{!./tutorial/src/nosql_databases/tutorial001.py!}
{!./src/nosql_databases/tutorial001.py!}
```
!!! note
@@ -97,7 +97,7 @@ Now create a function that will:
By creating a function that is only dedicated to getting your user from a `username` (or any other parameter) independent of your path operation function, you can more easily re-use it in multiple parts and also add <abbr title="Automated test, written in code, that checks if another piece of code is working correctly.">unit tests</abbr> for it:
```Python hl_lines="35 36 37 38 39 40 41"
{!./tutorial/src/nosql_databases/tutorial001.py!}
{!./src/nosql_databases/tutorial001.py!}
```
### f-strings
@@ -132,7 +132,7 @@ UserInDB(username="johndoe", hashed_password="some_hash")
### Create the `FastAPI` app
```Python hl_lines="45"
{!./tutorial/src/nosql_databases/tutorial001.py!}
{!./src/nosql_databases/tutorial001.py!}
```
### Create the path operation function
@@ -142,7 +142,7 @@ As our code is calling Couchbase and we are not using the <a href="https://docs.
Also, Couchbase recommends not using a single `Bucket` object in multiple "<abbr title="A sequence of code being executed by the program, while at the same time, or at intervals, there can be others being executed too.">thread</abbr>s", so, we can get just get the bucket directly and pass it to our utility functions:
```Python hl_lines="48 49 50 51 52"
{!./tutorial/src/nosql_databases/tutorial001.py!}
{!./src/nosql_databases/tutorial001.py!}
```
## Recap

View File

@@ -8,7 +8,7 @@ You can set the OpenAPI `operationId` to be used in your path operation with the
You would have to make sure that it is unique for each operation.
```Python hl_lines="6"
{!./tutorial/src/path_operation_advanced_configuration/tutorial001.py!}
{!./src/path_operation_advanced_configuration/tutorial001.py!}
```
## Exclude from OpenAPI
@@ -16,5 +16,5 @@ You would have to make sure that it is unique for each operation.
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`;
```Python hl_lines="6"
{!./tutorial/src/path_operation_advanced_configuration/tutorial002.py!}
{!./src/path_operation_advanced_configuration/tutorial002.py!}
```

View File

@@ -12,7 +12,7 @@ You can pass directly the `int` code, like `404`.
But if you don't remember what each number code is for, you can use the shortcut constants from `starlette`:
```Python hl_lines="5 18"
{!./tutorial/src/path_operation_configuration/tutorial001.py!}
{!./src/path_operation_configuration/tutorial001.py!}
```
That status code will be used in the response and will be added to the OpenAPI schema.
@@ -23,7 +23,7 @@ That status code will be used in the response and will be added to the OpenAPI s
You can add tags to your path operation, pass the parameter `tags` with a `list` of `str` (commonly just one `str`):
```Python hl_lines="17 22 27"
{!./tutorial/src/path_operation_configuration/tutorial002.py!}
{!./src/path_operation_configuration/tutorial002.py!}
```
They will be added to the OpenAPI schema and used by the automatic documentation interfaces:
@@ -35,7 +35,7 @@ They will be added to the OpenAPI schema and used by the automatic documentation
You can add a `summary` and `description`:
```Python hl_lines="20 21"
{!./tutorial/src/path_operation_configuration/tutorial003.py!}
{!./src/path_operation_configuration/tutorial003.py!}
```
## Description from docstring
@@ -43,7 +43,7 @@ You can add a `summary` and `description`:
As descriptions tend to be long and cover multiple lines, you can declare the path operation description in the function <abbr title="a multi-line string as the first expression inside a function (not assigned to any variable) used for documentation">docstring</abbr> and **FastAPI** will read it from there.
```Python hl_lines="19 20 21 22 23 24 25 26 27"
{!./tutorial/src/path_operation_configuration/tutorial004.py!}
{!./src/path_operation_configuration/tutorial004.py!}
```
It will be used in the interactive docs:
@@ -58,7 +58,7 @@ It will be used in the interactive docs:
You can specify the response description with the parameter `response_description`:
```Python hl_lines="21"
{!./tutorial/src/path_operation_configuration/tutorial005.py!}
{!./src/path_operation_configuration/tutorial005.py!}
```
!!! info
@@ -77,7 +77,7 @@ If you need to mark a path operation as <abbr title="obsolete, recommended not t
```Python hl_lines="16"
{!./tutorial/src/path_operation_configuration/tutorial006.py!}
{!./src/path_operation_configuration/tutorial006.py!}
```
It will be clearly marked as deprecated in the interactive docs:

View File

@@ -5,7 +5,7 @@ The same way you can declare more validations and metadata for query parameters
First, import `Path` from `fastapi`:
```Python hl_lines="1"
{!./tutorial/src/path_params_numeric_validations/tutorial001.py!}
{!./src/path_params_numeric_validations/tutorial001.py!}
```
## Declare metadata
@@ -15,7 +15,7 @@ You can declare all the same parameters as for `Query`.
For example, to declare a `title` metadata value for the path parameter `item_id` you can type:
```Python hl_lines="8"
{!./tutorial/src/path_params_numeric_validations/tutorial001.py!}
{!./src/path_params_numeric_validations/tutorial001.py!}
```
!!! note
@@ -42,7 +42,7 @@ It doesn't matter for **FastAPI**. It will detect the parameters by their names,
So, you can declare your function as:
```Python hl_lines="8"
{!./tutorial/src/path_params_numeric_validations/tutorial002.py!}
{!./src/path_params_numeric_validations/tutorial002.py!}
```
## Order the parameters as you need, tricks
@@ -54,7 +54,7 @@ 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 <abbr title="From: K-ey W-ord Arg-uments"><code>kwargs</code></abbr>. Even if they don't have a default value.
```Python hl_lines="8"
{!./tutorial/src/path_params_numeric_validations/tutorial003.py!}
{!./src/path_params_numeric_validations/tutorial003.py!}
```
## Number validations: greater than or equal
@@ -64,7 +64,7 @@ With `Query` and `Path` (and other's you'll see later) you can declare string co
Here, with `ge=1`, `item_id` will need to be an integer number "`g`reater than or `e`qual" to `1`.
```Python hl_lines="8"
{!./tutorial/src/path_params_numeric_validations/tutorial004.py!}
{!./src/path_params_numeric_validations/tutorial004.py!}
```
## Number validations: greater than and less than or equal
@@ -74,7 +74,7 @@ The same applies for:
* `le`: `l`ess than or `e`qual
```Python hl_lines="9"
{!./tutorial/src/path_params_numeric_validations/tutorial005.py!}
{!./src/path_params_numeric_validations/tutorial005.py!}
```
## Number validations: floats, greater than and less than
@@ -88,7 +88,7 @@ So, `0.5` would be a valid value. But `0.0` or `0` would not.
And the same for <abbr title="less than"><code>lt</code></abbr>.
```Python hl_lines="11"
{!./tutorial/src/path_params_numeric_validations/tutorial006.py!}
{!./src/path_params_numeric_validations/tutorial006.py!}
```
## Recap

View File

@@ -1,7 +1,7 @@
You can declare path "parameters" or "variables" with the same syntax used by Python format strings:
```Python hl_lines="6 7"
{!./tutorial/src/path_params/tutorial001.py!}
{!./src/path_params/tutorial001.py!}
```
The value of the path parameter `item_id` will be passed to your function as the argument `item_id`.
@@ -17,7 +17,7 @@ So, if you run this example and go to <a href="http://127.0.0.1:8000/items/foo"
You can declare the type of a path parameter in the function, using standard Python type annotations:
```Python hl_lines="7"
{!./tutorial/src/path_params/tutorial002.py!}
{!./src/path_params/tutorial002.py!}
```
In this case, `item_id` is declared to be an `int`.

View File

@@ -1,288 +0,0 @@
**Python 3.6+** has support for optional "type hints".
These **"type hints"** are a new syntax (since Python 3.6+) that allow declaring the <abbr title="for example: str, int, float, bool">type</abbr> of a variable.
By declaring types for your variables, editors and tools can give you better support.
This is just a **quick tutorial / refresher** about Python type hints. It covers only the minimum necessary to use them with **FastAPI**... which is actually very little.
**FastAPI** is all based on these type hints, they give it many advantages and benefits.
But even if you never use **FastAPI**, you would benefit from learning a bit about them.
!!! note
If you are a Python expert, and you already know everything about type hints, skip to the next chapter.
## Motivation
Let's start with a simple example:
```Python
{!./tutorial/src/python_types/tutorial001.py!}
```
Calling this program outputs:
```
John Doe
```
The function does the following:
* Takes a `fist_name` and `last_name`.
* Converts the first letter of each one to upper case with `title()`.
* <abbr title="Puts them together, as one. With the contents of one after the other.">Concatenates</abbr> them with a space in the middle.
```Python hl_lines="2"
{!./tutorial/src/python_types/tutorial001.py!}
```
### Edit it
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...
But then you have to call "that method that converts the first letter to upper case".
Was it `upper`? Was it `uppercase`? `first_uppercase`? `capitalize`?
Then, you try with the old programer's friend, editor autocompletion.
You type the first parameter of the function, `first_name`, then a dot (`.`) and then hit `Ctrl+Space` to trigger the completion.
But, sadly, you get nothing useful:
<img src="/img/tutorial/python-types/image01.png">
### Add types
Let's modify a single line from the previous version.
We will change exactly this fragment, the parameters of the function, from:
```Python
first_name, last_name
```
to:
```Python
first_name: str, last_name: str
```
That's it.
Those are the "type hints":
```Python hl_lines="1"
{!./tutorial/src/python_types/tutorial002.py!}
```
That is not the same as declaring default values like would be with:
```Python
first_name="john", last_name="doe"
```
It's a different thing.
We are using colons (`:`), not equals (`=`).
And adding type hints normally doesn't change what happens from what would happen without them.
But now, imagine you are again in the middle of creating that function, but with type hints.
At the same point, you try to trigger the autocomplete with `Ctrl+Space` and you see:
<img src="/img/tutorial/python-types/image02.png">
With that, you can scroll, seeing the options, until you find the one that "rings a bell":
<img src="/img/tutorial/python-types/image03.png">
## More motivation
Check this function, it already has type hints:
```Python hl_lines="1"
{!./tutorial/src/python_types/tutorial003.py!}
```
Because the editor knows the types of the variables, you don't only get completion, you also get error checks:
<img src="/img/tutorial/python-types/image04.png">
Now you know that you have to fix it, convert `age` to a string with `str(age)`:
```Python hl_lines="2"
{!./tutorial/src/python_types/tutorial004.py!}
```
## Declaring types
You just saw the main place to declare type hints. As function parameters.
This is also the main place you would use them with **FastAPI**.
### Simple types
You can declare all the standard Python types, not only `str`.
You can use, for example:
* `int`
* `float`
* `bool`
* `bytes`
```Python hl_lines="1"
{!./tutorial/src/python_types/tutorial005.py!}
```
### Types with subtypes
There are some data structures that can contain other values, like `dict`, `list`, `set` and `tuple`. And the internal values can have their own type too.
To declare those types and the subtypes, you can use the standard Python module `typing`.
It exists specifically to support these type hints.
#### Lists
For example, let's define a variable to be a `list` of `str`.
From `typing`, import `List` (with a capital `L`):
```Python hl_lines="1"
{!./tutorial/src/python_types/tutorial006.py!}
```
Declare the variable, with the same colon (`:`) syntax.
As the type, put the `List`.
As the list is a type that takes a "subtype", you put the subtype in square brackets:
```Python hl_lines="4"
{!./tutorial/src/python_types/tutorial006.py!}
```
That means: "the variable `items` is a `list`, and each of the items in this list is a `str`".
By doing that, your editor can provide support even while processing items from the list.
Without types, that's almost impossible to achieve:
<img src="/img/tutorial/python-types/image05.png">
Notice that the variable `item` is one of the elements in the list `items`.
And still, the editor knows it is a `str`, and provides support for that.
#### Tuples and Sets
You would do the same to declare `tuple`s and `set`s:
```Python hl_lines="1 4"
{!./tutorial/src/python_types/tutorial007.py!}
```
This means:
* The variable `items_t` is a `tuple`, and each of its items is an `int`.
* The variable `items_s` is a `set`, and each of its items is of type `bytes`.
#### Dicts
To define a `dict`, you pass 2 subtypes, separated by commas.
The first subtype is for the keys of the `dict`.
The second subtype is for the values of the `dict`:
```Python hl_lines="1 4"
{!./tutorial/src/python_types/tutorial008.py!}
```
This means:
* The variable `prices` is a `dict`:
* The keys of this `dict` are of type `str` (let's say, the name of each item).
* The values of this `dict` are of type `float` (let's say, the price of each item).
### Classes as types
You can also declare a class as the type of a variable.
Let's say you have a class `Person`, with a name:
```Python hl_lines="1 2 3"
{!./tutorial/src/python_types/tutorial009.py!}
```
Then you can declare a variable to be of type `Person`:
```Python hl_lines="6"
{!./tutorial/src/python_types/tutorial009.py!}
```
And then, again, you get all the editor support:
<img src="/img/tutorial/python-types/image06.png">
## Pydantic models
<a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic</a> is a Python library to perform data validation.
You declare the "shape" of the data as classes with attributes.
And each attribute has a type.
Then you create an instance of that class with some values and it will validate the values, convert them to the appropriate type (if that's the case) and give you an object with all the data.
And you get all the editor support with that resulting object.
Taken from the official Pydantic docs:
```Python
{!./tutorial/src/python_types/tutorial010.py!}
```
!!! info
To learn more about <a href="https://pydantic-docs.helpmanual.io/" target="_blank">Pydantic, check its docs</a>.
**FastAPI** is all based on Pydantic.
You will see a lot more of all this in practice in the next chapters.
## Type hints in **FastAPI**
**FastAPI** takes advantage of these type hints to do several things.
With **FastAPI** you declare parameters with type hints and you get:
* **Editor support**.
* **Type checks**.
...and **FastAPI** uses the same declarations to:
* **Define requirements**: from request path parameters, query parameters, headers, bodies, dependencies, etc.
* **Convert data**: from the request to the required type.
* **Validate data**: coming from each request:
* Generating **automatic errors** returned to the client when the data is invalid.
* **Document** the API using OpenAPI:
* which is then used by the automatic interactive documentation user interfaces.
This might all sound abstract. Don't worry. You'll see all this in action in the next chapters.
The important thing is that by using standard Python types, in a single place (instead of adding more classes, decorators, etc), **FastAPI** will do a lot of the work for you.
!!! info
If you already went through all the tutorial and came back to see more about types, a good resource is <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" target="_blank">the "cheat sheet" from `mypy`</a>.

View File

@@ -3,7 +3,7 @@
Let's take this application as example:
```Python hl_lines="7"
{!./tutorial/src/query_params_str_validations/tutorial001.py!}
{!./src/query_params_str_validations/tutorial001.py!}
```
The query parameter `q` is of type `str`, and by default is `None`, so it is optional.
@@ -18,7 +18,7 @@ We are going to enforce that even though `q` is optional, whenever it is provide
To achieve that, first import `Query` from `fastapi`:
```Python hl_lines="1"
{!./tutorial/src/query_params_str_validations/tutorial002.py!}
{!./src/query_params_str_validations/tutorial002.py!}
```
## Use `Query` as the default value
@@ -26,7 +26,7 @@ To achieve that, first import `Query` from `fastapi`:
And now use it as the default value of your parameter, setting the parameter `max_length` to 50:
```Python hl_lines="7"
{!./tutorial/src/query_params_str_validations/tutorial002.py!}
{!./src/query_params_str_validations/tutorial002.py!}
```
As we have to replace the default value `None` with `Query(None)`, the first parameter to `Query` serves the same purpose of defining that default value.
@@ -59,7 +59,7 @@ This will validate the data, show a clear error when the data is not valid, and
You can also add a parameter `min_length`:
```Python hl_lines="7"
{!./tutorial/src/query_params_str_validations/tutorial003.py!}
{!./src/query_params_str_validations/tutorial003.py!}
```
## Add regular expressions
@@ -67,7 +67,7 @@ You can also add a parameter `min_length`:
You can define a <abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings.">regular expression</abbr> that the parameter should match:
```Python hl_lines="8"
{!./tutorial/src/query_params_str_validations/tutorial004.py!}
{!./src/query_params_str_validations/tutorial004.py!}
```
This specific regular expression checks that the received parameter value:
@@ -87,7 +87,7 @@ The same way that you can pass `None` as the first argument to be used as the de
Let's say that you want to declare the `q` query parameter to have a `min_length` of `3`, and to have a default value of `"fixedquery"`:
```Python hl_lines="7"
{!./tutorial/src/query_params_str_validations/tutorial005.py!}
{!./src/query_params_str_validations/tutorial005.py!}
```
!!! note
@@ -116,7 +116,7 @@ q: str = Query(None, min_length=3)
So, when you need to declare a value as required while using `Query`, you can use `...` as the first argument:
```Python hl_lines="7"
{!./tutorial/src/query_params_str_validations/tutorial006.py!}
{!./src/query_params_str_validations/tutorial006.py!}
```
!!! info
@@ -133,13 +133,13 @@ That information will be included in the generated OpenAPI and used by the docum
You can add a `title`:
```Python hl_lines="7"
{!./tutorial/src/query_params_str_validations/tutorial007.py!}
{!./src/query_params_str_validations/tutorial007.py!}
```
And a `description`:
```Python hl_lines="11"
{!./tutorial/src/query_params_str_validations/tutorial008.py!}
{!./src/query_params_str_validations/tutorial008.py!}
```
## Alias parameters
@@ -161,7 +161,7 @@ But you still need it to be exactly `item-query`...
Then you can declare an `alias`, and that alias is what will be used to find the parameter value:
```Python hl_lines="7"
{!./tutorial/src/query_params_str_validations/tutorial009.py!}
{!./src/query_params_str_validations/tutorial009.py!}
```
## Deprecating parameters
@@ -173,7 +173,7 @@ You have to leave it there a while because there are clients using it, but you w
Then pass the parameter `deprecated=True` to `Query`:
```Python hl_lines="16"
{!./tutorial/src/query_params_str_validations/tutorial010.py!}
{!./src/query_params_str_validations/tutorial010.py!}
```
The docs will show it like this:

View File

@@ -1,7 +1,7 @@
When you declare other function parameters that are not part of the path parameters, they are automatically interpreted as "query" parameters.
```Python hl_lines="9"
{!./tutorial/src/query_params/tutorial001.py!}
{!./src/query_params/tutorial001.py!}
```
The query is the set of key-value pairs that go after the `?` in a URL, separated by `&` characters.
@@ -62,7 +62,7 @@ The parameter values in your function will be:
The same way, you can declare optional query parameters, by setting their default to `None`:
```Python hl_lines="7"
{!./tutorial/src/query_params/tutorial002.py!}
{!./src/query_params/tutorial002.py!}
```
In this case, the function parameter `q` will be optional, and will be `None` by default.
@@ -75,7 +75,7 @@ In this case, the function parameter `q` will be optional, and will be `None` by
You can also declare `bool` types, and they will be converted:
```Python hl_lines="7"
{!./tutorial/src/query_params/tutorial003.py!}
{!./src/query_params/tutorial003.py!}
```
In this case, if you go to:
@@ -120,7 +120,7 @@ And you don't have to declare them in any specific order.
They will be detected by name:
```Python hl_lines="6 8"
{!./tutorial/src/query_params/tutorial004.py!}
{!./src/query_params/tutorial004.py!}
```
## Required query parameters
@@ -132,7 +132,7 @@ If you don't want to add a specific value but just make it optional, set the def
But when you want to make a query parameter required, you can just do not declare any default value:
```Python hl_lines="6 7"
{!./tutorial/src/query_params/tutorial005.py!}
{!./src/query_params/tutorial005.py!}
```
Here the query parameter `needy` is a required query parameter of type `str`.
@@ -178,7 +178,7 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
And of course, you can define some parameters as required, some as having a default value, and some entirely optional:
```Python hl_lines="7"
{!./tutorial/src/query_params/tutorial006.py!}
{!./src/query_params/tutorial006.py!}
```
In this case, there are 3 query parameters:

View File

@@ -5,7 +5,7 @@ You can define files to be uploaded by the client using `File`.
Import `File` from `fastapi`:
```Python hl_lines="1"
{!./tutorial/src/request_files/tutorial001.py!}
{!./src/request_files/tutorial001.py!}
```
## Define `File` parameters
@@ -13,7 +13,7 @@ Import `File` from `fastapi`:
Create file parameters the same way you would for `Body` or `Form`:
```Python hl_lines="7"
{!./tutorial/src/request_files/tutorial001.py!}
{!./src/request_files/tutorial001.py!}
```
The files will be uploaded as form data and you will receive the contents as `bytes`.

View File

@@ -3,7 +3,7 @@ You can define files and form fields at the same time using `File` and `Form`.
## Import `File` and `Form`
```Python hl_lines="1"
{!./tutorial/src/request_forms_and_files/tutorial001.py!}
{!./src/request_forms_and_files/tutorial001.py!}
```
## Define `File` and `Form` parameters
@@ -11,7 +11,7 @@ You can define files and form fields at the same time using `File` and `Form`.
Create file and form parameters the same way you would for `Body` or `Query`:
```Python hl_lines="7"
{!./tutorial/src/request_forms_and_files/tutorial001.py!}
{!./src/request_forms_and_files/tutorial001.py!}
```
The files and form fields will be uploaded as form data and you will receive the files and form fields.

View File

@@ -5,7 +5,7 @@ When you need to receive form fields instead of JSON, you can use `Form`.
Import `Form` from `fastapi`:
```Python hl_lines="1"
{!./tutorial/src/request_forms/tutorial001.py!}
{!./src/request_forms/tutorial001.py!}
```
## Define `Form` parameters
@@ -13,7 +13,7 @@ Import `Form` from `fastapi`:
Create form parameters the same way you would for `Body` or `Query`:
```Python hl_lines="7"
{!./tutorial/src/request_forms/tutorial001.py!}
{!./src/request_forms/tutorial001.py!}
```
For example, in one of the ways the OAuth2 specification can be used (called "password flow") it is required to send a `username` and `password` as form fields.

View File

@@ -7,7 +7,7 @@ You can declare the model used for the response with the parameter `response_mod
* etc.
```Python hl_lines="17"
{!./tutorial/src/response_model/tutorial001.py!}
{!./src/response_model/tutorial001.py!}
```
!!! note
@@ -29,13 +29,13 @@ But most importantly:
Here we are declaring a `UserIn` model, it will contain a plaintext password:
```Python hl_lines="8 10"
{!./tutorial/src/response_model/tutorial002.py!}
{!./src/response_model/tutorial002.py!}
```
And we are using this model to declare our input and the same model to declare our output:
```Python hl_lines="16 17"
{!./tutorial/src/response_model/tutorial002.py!}
{!./src/response_model/tutorial002.py!}
```
Now, whenever a browser is creating a user with a password, the API will return the same password in the response.
@@ -52,19 +52,19 @@ But if we use sthe same model for another path operation, we could be sending th
We can instead create an input model with the plaintext password and an output model without it:
```Python hl_lines="8 10 15"
{!./tutorial/src/response_model/tutorial003.py!}
{!./src/response_model/tutorial003.py!}
```
Here, even though our path operation function is returning the same input user that contains the password:
```Python hl_lines="23"
{!./tutorial/src/response_model/tutorial003.py!}
{!./src/response_model/tutorial003.py!}
```
...we declared the `response_model` to be our model `UserOut`, that doesn't include the password:
```Python hl_lines="21"
{!./tutorial/src/response_model/tutorial003.py!}
{!./src/response_model/tutorial003.py!}
```
So, **FastAPI** will take care of filtering out all the data that is not declared in the output model (using Pydantic).

View File

@@ -1,5 +1,5 @@
Coming soon...
```Python
{!./tutorial/src/security/tutorial002.py!}
{!./src/security/tutorial002.py!}
```

View File

@@ -1,5 +1,5 @@
Coming soon...
```Python
{!./tutorial/src/security/tutorial001.py!}
{!./src/security/tutorial001.py!}
```

View File

@@ -1,5 +1,5 @@
Coming soon...
```Python
{!./tutorial/src/security/tutorial004.py!}
{!./src/security/tutorial004.py!}
```

View File

@@ -1,5 +1,5 @@
Coming soon...
```Python
{!./tutorial/src/security/tutorial003.py!}
{!./src/security/tutorial003.py!}
```

View File

@@ -24,7 +24,7 @@ In this example, we'll use **PostgreSQL**.
For now, don't pay attention to the rest, only the imports:
```Python hl_lines="3 4 5"
{!./tutorial/src/sql_databases/tutorial001.py!}
{!./src/sql_databases/tutorial001.py!}
```
## Define the database
@@ -32,7 +32,7 @@ For now, don't pay attention to the rest, only the imports:
Define the database that SQLAlchemy should connect to:
```Python hl_lines="8"
{!./tutorial/src/sql_databases/tutorial001.py!}
{!./src/sql_databases/tutorial001.py!}
```
!!! tip
@@ -41,13 +41,13 @@ Define the database that SQLAlchemy should connect to:
## Create the SQLAlchemy `engine`
```Python hl_lines="10"
{!./tutorial/src/sql_databases/tutorial001.py!}
{!./src/sql_databases/tutorial001.py!}
```
## Create a `scoped_session`
```Python hl_lines="11 12 13"
{!./tutorial/src/sql_databases/tutorial001.py!}
{!./src/sql_databases/tutorial001.py!}
```
!!! note "Very Technical Details"
@@ -70,13 +70,13 @@ That way you don't have to declare them explicitly.
So, your models will behave very similarly to, for example, Flask-SQLAlchemy.
```Python hl_lines="15 16 17 18 19"
{!./tutorial/src/sql_databases/tutorial001.py!}
{!./src/sql_databases/tutorial001.py!}
```
## Create the SQLAlchemy `Base` model
```Python hl_lines="22"
{!./tutorial/src/sql_databases/tutorial001.py!}
{!./src/sql_databases/tutorial001.py!}
```
## Create your application data model
@@ -86,7 +86,7 @@ Now this is finally code specific to your app.
Here's a user model that will be a table in the database:
```Python hl_lines="25 26 27 28 29"
{!./tutorial/src/sql_databases/tutorial001.py!}
{!./src/sql_databases/tutorial001.py!}
```
## Get a user
@@ -94,7 +94,7 @@ Here's a user model that will be a table in the database:
By creating a function that is only dedicated to getting your user from a `username` (or any other parameter) independent of your path operation function, you can more easily re-use it in multiple parts and also add <abbr title="Automated test, written in code, that checks if another piece of code is working correctly.">unit tests</abbr> for it:
```Python hl_lines="32 33"
{!./tutorial/src/sql_databases/tutorial001.py!}
{!./src/sql_databases/tutorial001.py!}
```
## Create your **FastAPI** code
@@ -104,7 +104,7 @@ Now, finally, here's the standard **FastAPI** code.
Create your app and path operation function:
```Python hl_lines="37 40 41 42 43"
{!./tutorial/src/sql_databases/tutorial001.py!}
{!./src/sql_databases/tutorial001.py!}
```
As we are using SQLAlchemy's `scoped_session`, we don't even have to create a dependency with `Depends`.
@@ -132,7 +132,7 @@ user = get_user(username, db_session)
Then we should declare the path operation without `async def`, just with a normal `def`:
```Python hl_lines="41"
{!./tutorial/src/sql_databases/tutorial001.py!}
{!./src/sql_databases/tutorial001.py!}
```
## Migrations

View File

@@ -1,12 +0,0 @@
from fastapi import FastAPI
app = FastAPI(
title="My Super Project",
description="This is a very fancy project, with auto docs for the API and everything",
version="2.5.0",
)
@app.get("/items/")
async def read_items():
return [{"name": "Foo"}]

View File

@@ -1,10 +0,0 @@
from fastapi import FastAPI
app = FastAPI(
title="My Super Project", version="2.5.0", openapi_url="/api/v1/openapi.json"
)
@app.get("/items/")
async def read_items():
return [{"name": "Foo"}]

View File

@@ -1,14 +0,0 @@
from fastapi import FastAPI
app = FastAPI(
title="My Super Project",
version="2.5.0",
openapi_url="/api/v1/openapi.json",
docs_url="/api/v1/docs",
redoc_url=None,
)
@app.get("/items/")
async def read_items():
return [{"name": "Foo"}]

View File

@@ -1,18 +0,0 @@
from fastapi import APIRouter
router = APIRouter()
@router.get("/users/")
async def read_users():
return [{"username": "Foo"}, {"username": "Bar"}]
@router.get("/users/me")
async def read_user_me():
return {"username": "fakecurrentuser"}
@router.get("/users/{username}")
async def read_user(username: str):
return {"username": username}

View File

@@ -1,13 +0,0 @@
from fastapi import APIRouter
router = APIRouter()
@router.get("/")
async def read_items():
return [{"name": "Item Foo"}, {"name": "item Bar"}]
@router.get("/{item_id}")
async def read_item(item_id: str):
return {"name": "Fake Specific Item", "item_id": item_id}

View File

@@ -1,9 +0,0 @@
from fastapi import FastAPI
from .routers.tutorial001 import router as users_router
from .routers.tutorial002 import router as items_router
app = FastAPI()
app.include_router(users_router)
app.include_router(items_router, prefix="/items")

View File

@@ -1,17 +0,0 @@
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item

View File

@@ -1,21 +0,0 @@
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
item_dict = item.dict()
if item.tax:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return item_dict

View File

@@ -1,17 +0,0 @@
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
app = FastAPI()
@app.put("/items/{item_id}")
async def create_item(item_id: int, item: Item):
return {"item_id": item_id, **item.dict()}

View File

@@ -1,20 +0,0 @@
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
app = FastAPI()
@app.put("/items/{item_id}")
async def create_item(item_id: int, item: Item, q: str = None):
result = {"item_id": item_id, **item.dict()}
if q:
result.update({"q": q})
return result

View File

@@ -1,26 +0,0 @@
from fastapi import FastAPI, Path
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = 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: str = None,
item: Item = None,
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
if item:
results.update({"item": item})
return results

View File

@@ -1,22 +0,0 @@
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
class User(BaseModel):
username: str
full_name: str = 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

View File

@@ -1,24 +0,0 @@
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
class User(BaseModel):
username: str
full_name: str = 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

View File

@@ -1,31 +0,0 @@
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
class User(BaseModel):
username: str
full_name: str = None
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int,
item: Item,
user: User,
importance: int = Body(..., gt=0),
q: str = None
):
results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
if q:
results.update({"q": q})
return results

View File

@@ -1,17 +0,0 @@
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = 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

View File

@@ -1,18 +0,0 @@
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = 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

View File

@@ -1,20 +0,0 @@
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = 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

View File

@@ -1,20 +0,0 @@
from typing import Set
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = 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

View File

@@ -1,26 +0,0 @@
from typing import Set
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Image(BaseModel):
url: str
name: str
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
tags: Set[str] = []
image: Image = None
@app.put("/items/{item_id}")
async def update_item(*, item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results

View File

@@ -1,27 +0,0 @@
from typing import Set
from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.types import UrlStr
app = FastAPI()
class Image(BaseModel):
url: UrlStr
name: str
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
tags: Set[str] = []
image: Image = None
@app.put("/items/{item_id}")
async def update_item(*, item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results

View File

@@ -1,27 +0,0 @@
from typing import List, Set
from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.types import UrlStr
app = FastAPI()
class Image(BaseModel):
url: UrlStr
name: str
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
tags: Set[str] = []
image: List[Image] = None
@app.put("/items/{item_id}")
async def update_item(*, item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results

View File

@@ -1,33 +0,0 @@
from typing import List, Set
from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.types import UrlStr
app = FastAPI()
class Image(BaseModel):
url: UrlStr
name: str
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
tags: Set[str] = []
image: List[Image] = None
class Offer(BaseModel):
name: str
description: str = None
price: float
items: List[Item]
@app.post("/offers/")
async def create_offer(*, offer: Offer):
return offer

View File

@@ -1,17 +0,0 @@
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.types import UrlStr
app = FastAPI()
class Image(BaseModel):
url: UrlStr
name: str
@app.post("/images/multiple/")
async def create_multiple_images(*, images: List[Image]):
return images

View File

@@ -1,17 +0,0 @@
from fastapi import Body, FastAPI
from pydantic import BaseModel, Schema
app = FastAPI()
class Item(BaseModel):
name: str
description: str = Schema(None, title="The description of the item", max_length=300)
price: float = Schema(..., gt=0, description="The price must be greater than zero")
tax: float = 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

View File

@@ -1,29 +0,0 @@
from fastapi import Body, FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
@app.put("/items/{item_id}")
async def update_item(
*,
item_id: int,
item: Item = Body(
...,
example={
"name": "Foo",
"description": "A very nice Item",
"price": 35.4,
"tax": 3.2,
},
)
):
results = {"item_id": item_id, "item": item}
return results

View File

@@ -1,8 +0,0 @@
from fastapi import Cookie, FastAPI
app = FastAPI()
@app.get("/items/")
async def read_items(*, ads_id: str = Cookie(None)):
return {"ads_id": ads_id}

View File

@@ -1,9 +0,0 @@
from fastapi import FastAPI
from starlette.responses import UJSONResponse
app = FastAPI()
@app.get("/items/", content_type=UJSONResponse)
async def read_items():
return [{"item_id": "Foo"}]

View File

@@ -1,18 +0,0 @@
from fastapi import FastAPI
from starlette.responses import HTMLResponse
app = FastAPI()
@app.get("/items/", content_type=HTMLResponse)
async def read_items():
return """
<html>
<head>
<title>Some HTML in here</title>
</head>
<body>
<h1>Look ma! HTML!</h1>
</body>
</html>
"""

View File

@@ -1,19 +0,0 @@
from fastapi import FastAPI
from starlette.responses import HTMLResponse
app = FastAPI()
@app.get("/items/")
async def read_items():
html_content = """
<html>
<head>
<title>Some HTML in here</title>
</head>
<body>
<h1>Look ma! HTML!</h1>
</body>
</html>
"""
return HTMLResponse(content=html_content, status_code=200)

View File

@@ -1,23 +0,0 @@
from fastapi import FastAPI
from starlette.responses import HTMLResponse
app = FastAPI()
def generate_html_response():
html_content = """
<html>
<head>
<title>Some HTML in here</title>
</head>
<body>
<h1>Look ma! HTML!</h1>
</body>
</html>
"""
return HTMLResponse(content=html_content, status_code=200)
@app.get("/items/", content_type=HTMLResponse)
async def read_items():
return generate_html_response()

View File

@@ -1,12 +0,0 @@
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str = 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

View File

@@ -1,27 +0,0 @@
from fastapi import Depends, FastAPI
from pydantic import BaseModel
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams(BaseModel):
q: str = None
skip: int = None
limit: int = None
async def common_parameters(q: str = None, skip: int = 0, limit: int = 100):
return CommonQueryParams(q=q, skip=skip, limit=limit)
@app.get("/items/")
async def read_items(commons: CommonQueryParams = Depends(common_parameters)):
response = {}
if commons.q:
response.update({"q": commons.q})
items = fake_items_db[commons.skip : commons.limit]
response.update({"items": items})
return response

View File

@@ -1,34 +0,0 @@
from typing import List
from fastapi import Cookie, Depends, FastAPI
from pydantic import BaseModel
app = FastAPI()
class InterestsTracker(BaseModel):
track_code: str
interests: List[str]
fake_tracked_users_db = {
"Foo": {"track_code": "Foo", "interests": ["sports", "movies"]},
"Bar": {"track_code": "Bar", "interests": ["food", "shows"]},
"Baz": {"track_code": "Baz", "interests": ["gaming", "virtual reality"]},
}
async def get_tracked_interests(track_code: str = Cookie(None)):
if track_code in fake_tracked_users_db:
track_dict = fake_tracked_users_db[track_code]
track = InterestsTracker(**track_dict)
return track
return None
@app.get("/interests/")
async def read_interests(
tracked_interests: InterestsTracker = Depends(get_tracked_interests)
):
response = {"interests": tracked_interests.interests}
return response

View File

@@ -1,49 +0,0 @@
from random import choice
from typing import List
from fastapi import Cookie, Depends, FastAPI
from pydantic import BaseModel
app = FastAPI()
class InterestsTracker(BaseModel):
track_code: str
interests: List[str]
fake_tracked_users_db = {
"Foo": {"track_code": "Foo", "interests": ["sports", "movies"]},
"Bar": {"track_code": "Bar", "interests": ["food", "shows"]},
"Baz": {"track_code": "Baz", "interests": ["gaming", "virtual reality"]},
}
async def get_tracked_interests(track_code: str = Cookie(None)):
if track_code in fake_tracked_users_db:
track_dict = fake_tracked_users_db[track_code]
track = InterestsTracker(**track_dict)
return track
return None
class ComplexTracker:
def __init__(self, tracker: InterestsTracker = Depends(get_tracked_interests)):
self.tracker = tracker
def random_interest(self):
"""
Get a random interest from the tracked ones for the current user.
If the user doesn't have tracked interests, return a random one from the ones available.
"""
if self.tracker.interests:
return choice(self.tracker.interests)
return choice(
["sports", "movies", "food", "shows", "gaming", "virtual reality"]
)
@app.get("/suggested-category")
async def read_suggested_category(tracker: ComplexTracker = Depends(None)):
response = {"category": tracker.random_interest()}
return response

View File

@@ -1,42 +0,0 @@
from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.types import EmailStr
app = FastAPI()
class UserIn(BaseModel):
username: str
password: str
email: EmailStr
full_name: str = None
class UserOut(BaseModel):
username: str
email: EmailStr
full_name: str = None
class UserInDB(BaseModel):
username: str
hashed_password: str
email: EmailStr
full_name: str = 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.dict(), 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

View File

@@ -1,40 +0,0 @@
from fastapi import FastAPI
from pydantic import BaseModel
from pydantic.types import EmailStr
app = FastAPI()
class UserBase(BaseModel):
username: str
email: EmailStr
full_name: str = 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.dict(), 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

View File

@@ -1,8 +0,0 @@
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}

View File

@@ -1,8 +0,0 @@
from fastapi import FastAPI
my_awesome_api = FastAPI()
@my_awesome_api.get("/")
async def root():
return {"message": "Hello World"}

View File

@@ -1,8 +0,0 @@
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"message": "Hello World"}

View File

@@ -1,8 +0,0 @@
from fastapi import FastAPI, Header
app = FastAPI()
@app.get("/items/")
async def read_items(*, user_agent: str = Header(None)):
return {"User-Agent": user_agent}

View File

@@ -1,8 +0,0 @@
from fastapi import FastAPI, Header
app = FastAPI()
@app.get("/items/")
async def read_items(*, strange_header: str = Header(None, convert_underscores=False)):
return {"strange_header": strange_header}

View File

@@ -1,54 +0,0 @@
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
from couchbase import LOCKMODE_WAIT
from couchbase.bucket import Bucket
from couchbase.cluster import Cluster, PasswordAuthenticator
USERPROFILE_DOC_TYPE = "userprofile"
def get_bucket():
cluster = Cluster(
"couchbase://couchbasehost:8091?fetch_mutation_tokens=1&operation_timeout=30&n1ql_timeout=300"
)
authenticator = PasswordAuthenticator("username", "password")
cluster.authenticate(authenticator)
bucket: Bucket = cluster.open_bucket("bucket_name", lockmode=LOCKMODE_WAIT)
bucket.timeout = 30
bucket.n1ql_timeout = 300
return bucket
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
disabled: Optional[bool] = None
class UserInDB(User):
type: str = USERPROFILE_DOC_TYPE
hashed_password: str
def get_user(bucket: Bucket, username: str):
doc_id = f"userprofile::{username}"
result = bucket.get(doc_id, quiet=True)
if not result.value:
return None
user = UserInDB(**result.value)
return user
# FastAPI specific code
app = FastAPI()
@app.get("/users/{username}", response_model=User)
def read_user(username: str):
bucket = get_bucket()
user = get_user(bucket=bucket, username=username)
return user

View File

@@ -1,8 +0,0 @@
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/", operation_id="some_specific_id_you_define")
async def read_items():
return [{"item_id": "Foo"}]

View File

@@ -1,8 +0,0 @@
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/", include_in_schema=False)
async def read_items():
return [{"item_id": "Foo"}]

View File

@@ -1,20 +0,0 @@
from typing import Set
from fastapi import FastAPI
from pydantic import BaseModel
from starlette.status import HTTP_201_CREATED
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
tags: Set[str] = []
@app.post("/items/", response_model=Item, status_code=HTTP_201_CREATED)
async def create_item(*, item: Item):
return item

View File

@@ -1,29 +0,0 @@
from typing import Set
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
tags: Set[str] = []
@app.post("/items/", response_model=Item, tags=["items"])
async def create_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"}]

View File

@@ -1,24 +0,0 @@
from typing import Set
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
tags: Set[str] = []
@app.post(
"/items/",
response_model=Item,
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):
return item

View File

@@ -1,28 +0,0 @@
from typing import Set
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
tags: Set[str] = []
@app.post("/items/", response_model=Item, summary="Create an item")
async def create_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

View File

@@ -1,33 +0,0 @@
from typing import Set
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
tags: Set[str] = []
@app.post(
"/items/",
response_model=Item,
summary="Create an item",
response_description="The created item",
)
async def create_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

View File

@@ -1,18 +0,0 @@
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"}]

View File

@@ -1,8 +0,0 @@
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id):
return {"item_id": item_id}

View File

@@ -1,8 +0,0 @@
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id}

View File

@@ -1,10 +0,0 @@
from uuid import UUID
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: UUID):
return {"item_id": item_id}

View File

@@ -1,14 +0,0 @@
from fastapi import FastAPI, Path, Query
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 = Query(None, alias="item-query"),
):
results = {"item_id": item_id}
if q:
results.update({"q": q})
return results

View File

@@ -1,13 +0,0 @@
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

View File

@@ -1,13 +0,0 @@
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

View File

@@ -1,13 +0,0 @@
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

View File

@@ -1,15 +0,0 @@
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

View File

@@ -1,16 +0,0 @@
from fastapi import FastAPI, Path, Query
app = FastAPI()
@app.get("/items/{item_id}")
async def read_items(
*,
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})
return results

View File

@@ -1,6 +0,0 @@
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"))

View File

@@ -1,6 +0,0 @@
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"))

View File

@@ -1,3 +0,0 @@
def get_name_with_age(name: str, age: int):
name_with_age = name + " is this old: " + age
return name_with_age

View File

@@ -1,3 +0,0 @@
def get_name_with_age(name: str, age: int):
name_with_age = name + " is this old: " + str(age)
return name_with_age

View File

@@ -1,2 +0,0 @@
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_d, item_e

View File

@@ -1,6 +0,0 @@
from typing import List
def process_items(items: List[str]):
for item in items:
print(item)

View File

@@ -1,5 +0,0 @@
from typing import Set, Tuple
def process_items(items_t: Tuple[int], items_s: Set[bytes]):
return items_t, items_s

View File

@@ -1,7 +0,0 @@
from typing import Dict
def process_items(prices: Dict[str, float]):
for item_name, item_price in prices.items():
print(item_name)
print(item_price)

Some files were not shown because too many files have changed in this diff Show More