-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
33 changed files
with
606 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,4 +18,5 @@ wtf | |
.mypy_cache | ||
coverage.json | ||
site | ||
wtf.py | ||
wtf.py | ||
CODE_OF_CONDUCT.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
# CustomField | ||
|
||
!!! warning "Packages developers" | ||
This is the part of documentation will talks you about some features, that can be helpfull to develop your own packages with `FastDepends` | ||
|
||
## Custom Arguments Field | ||
|
||
If you wish to write your own **FastAPI** or another closely by architecture tool, you | ||
should define your own custom fields to specify application behavior. At **FastAPI** these fields are: | ||
|
||
* Body | ||
* Path | ||
* Query | ||
* Header | ||
* Cookie | ||
* Form | ||
* File | ||
* Security | ||
|
||
Custom fields can be used to adding something specific to a function arguments (like a *BackgroundTask*) or | ||
parsing incoming objects special way. You able decide by own, why and how you will use these tools. | ||
|
||
`FastDepends` grants you this opportunity a very intuitive and comfortable way. | ||
|
||
### Let's write *Header* | ||
|
||
As an example, will try to implement **FastAPI** *Header* field | ||
|
||
```python linenums="1" hl_lines="1 3-4" | ||
{!> docs_src/advanced/custom/class_declaration.py !} | ||
``` | ||
|
||
Just import `fast_depends.library.CustomField` and implements `use` (async or sync) method. | ||
That's all. We already have own *Header* field to parse **kwargs** the special way. | ||
|
||
### *Header* usage | ||
|
||
Now we already can use the *Header* field | ||
|
||
```python linenums="1" hl_lines="4 8" | ||
{!> docs_src/advanced/custom/usage.py !} | ||
``` | ||
|
||
As we defined, *Header* parse incoming **headers kwargs field**, get a parameter by name and put it to | ||
original function as an argument. | ||
|
||
### More details | ||
|
||
`CustomField` has some fields you should know about | ||
|
||
```python | ||
class CustomField: | ||
param_name: str | ||
cast: bool | ||
``` | ||
|
||
* `param_name` - an original function argument name to replace by your field instance. It was `header_field` at the example above. | ||
* `cast` - specify the typecasting behavior. Use *False* to disable pydantic typecasting for fields using with your *CustomField* | ||
|
||
```python linenums="1" hl_lines="3 8 12-13" | ||
{!> docs_src/advanced/custom/cast_arg.py !} | ||
``` | ||
|
||
!!! note | ||
Pydantic understands only python-native annotation or Pydantic classes. If users will annotate your fields by other classes, | ||
you should set `cast=False` to avoid pydantic exeptions. | ||
|
||
```python | ||
def use(self, **kwargs: AnyDict) -> AnyDict: ... | ||
``` | ||
|
||
Your *CustimField* objects receive casted to *kwargs* an original function incoming arguments at `use` method. | ||
Returning from the `use` method dict replace an original one. Original function will be executed **with a returned from your fields kwargs**. | ||
Be accurate with. | ||
|
||
And one more time: | ||
|
||
```python linenums="1" hl_lines="6 9" | ||
original_kwargs = { "headers": { "field": 1 }} | ||
|
||
new_kwargs = Header().set_param_name("field").use(**kwargs) | ||
# new_kwargs = { | ||
# "headers": { "field": 1 }, | ||
# "field": 1 <-- new field from Header | ||
# } | ||
|
||
original_function(**new_kwargs) | ||
``` | ||
|
||
I hope it was clearly enough right now. | ||
|
||
Also, custom fields using according their definition: from left to right. | ||
Next Custom Fields **kwargs** is a return of previous. | ||
|
||
An example: | ||
|
||
```python linenums="1" | ||
@inject | ||
def func(field1 = Header(), field2 = Header()): ... | ||
``` | ||
|
||
**field2** incoming kwargs is an output of **field1.use()** |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# Let's write some code | ||
|
||
Now we take the *starlette example* from [usages](/FastDepends/usages/) and specify it to use *Path* now. | ||
|
||
## Handle *request* specific fields | ||
|
||
First of all, **Starlette** pass to a handler the only one argument - `request` | ||
To use them with `FastDepends` we need unwrap `request` to kwargs. | ||
|
||
```python hl_lines="6-8" linenums="1" | ||
{!> docs_src/advanced/custom/starlette.py [ln:1,16-21] !} | ||
``` | ||
|
||
!!! note "" | ||
Also, we wraps an original handler to `fast_depends.inject` too at *3* line | ||
|
||
## Declare *Custom Field* | ||
|
||
Next step, define *Path* custom field | ||
|
||
```python linenums="1" hl_lines="8" | ||
{!> docs_src/advanced/custom/starlette.py [ln:2,8-13] !} | ||
``` | ||
|
||
## Usage with the *Starlette* | ||
|
||
And use it at our *Starlette* application: | ||
```python linenums="1" hl_lines="6 7 10" | ||
{!> docs_src/advanced/custom/starlette.py [ln:4-6,23-30] !} | ||
``` | ||
|
||
Depends is working as expected too | ||
|
||
```python linenums="1" hl_lines="1 4-5 9" | ||
def get_user(user_id: int = Path()): | ||
return f"user {user_id}" | ||
|
||
@wrap_starlette | ||
async def hello(user: str = Depends(get_user)): | ||
return PlainTextResponse(f"Hello, {user}!") | ||
|
||
app = Starlette(debug=True, routes=[ | ||
Route("/{user_id}", hello) | ||
]) | ||
``` | ||
|
||
As an *Annotated* does | ||
```python linenums="1" hl_lines="2" | ||
@wrap_starlette | ||
async def get_user(user: Annotated[int, Path()]): | ||
return PlainTextResponse(f"Hello, {user}!") | ||
``` | ||
|
||
## Full example | ||
|
||
```python linenums="1" | ||
{!> docs_src/advanced/custom/starlette.py !} | ||
``` | ||
|
||
The code above works "as it". You can copy it and declare other *Header*, *Cookie*, *Query* fields by yourself. Just try, it's fun! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.