mirror of
https://github.com/fastapi/fastapi.git
synced 2025-12-24 06:39:31 -05:00
Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
148bcf5ce4 | ||
|
|
e4c8df062b | ||
|
|
b313f86338 | ||
|
|
9293795e99 | ||
|
|
58757f63af | ||
|
|
88dc4ce3d7 | ||
|
|
c9d3656a6e | ||
|
|
3e4840f21b | ||
|
|
9cb2586499 | ||
|
|
8b62319d6c | ||
|
|
6e3c707c60 | ||
|
|
94fa151881 | ||
|
|
a4f3bc5a69 | ||
|
|
05342cc264 | ||
|
|
8115282ed3 | ||
|
|
9ad2cb29f9 | ||
|
|
23d0efa894 | ||
|
|
e1129af819 | ||
|
|
c59539913d | ||
|
|
7a64587d7f | ||
|
|
62fc0b4923 | ||
|
|
fc7da62005 | ||
|
|
40df42f5c7 | ||
|
|
0b0af37b0e | ||
|
|
73920366e5 | ||
|
|
682067cab2 | ||
|
|
ca30b92dd7 | ||
|
|
72b542d90a | ||
|
|
9012ab8bcd | ||
|
|
9530defba8 | ||
|
|
7c23bbd96f | ||
|
|
11b6c0146d | ||
|
|
4e29835609 | ||
|
|
9858577cd6 | ||
|
|
cd1ee83435 | ||
|
|
fe74890b4b | ||
|
|
97a2ebc219 | ||
|
|
805226c2b0 | ||
|
|
5905c3f740 | ||
|
|
00f3c831f3 | ||
|
|
e84cb6663e | ||
|
|
fb8e9083f4 | ||
|
|
6b83525ff4 | ||
|
|
fba7493042 | ||
|
|
53973f7f94 | ||
|
|
1562592bde | ||
|
|
52a84175c1 | ||
|
|
929289b630 |
@@ -1,5 +1,3 @@
|
||||
name: Question or Problem
|
||||
description: Ask a question or ask about a problem
|
||||
labels: [question]
|
||||
body:
|
||||
- type: markdown
|
||||
@@ -9,9 +7,9 @@ body:
|
||||
|
||||
Please follow these instructions, fill every question, and do every step. 🙏
|
||||
|
||||
I'm asking this because answering questions and solving problems in GitHub issues is what consumes most of the time.
|
||||
I'm asking this because answering questions and solving problems in GitHub is what consumes most of the time.
|
||||
|
||||
I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling issues.
|
||||
I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling questions.
|
||||
|
||||
All that, on top of all the incredible help provided by a bunch of community members, the [FastAPI Experts](https://fastapi.tiangolo.com/fastapi-people/#experts), that give a lot of their time to come here and help others.
|
||||
|
||||
@@ -21,16 +19,16 @@ body:
|
||||
|
||||
And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎
|
||||
|
||||
As there are too many issues with questions, I'll have to close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓
|
||||
As there are too many questions, I'll have to discard and close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: First Check
|
||||
description: Please confirm and check all the following options.
|
||||
options:
|
||||
- label: I added a very descriptive title to this issue.
|
||||
- label: I added a very descriptive title here.
|
||||
required: true
|
||||
- label: I used the GitHub search to find a similar issue and didn't find it.
|
||||
- label: I used the GitHub search to find a similar question and didn't find it.
|
||||
required: true
|
||||
- label: I searched the FastAPI documentation, with the integrated search.
|
||||
required: true
|
||||
@@ -51,9 +49,9 @@ body:
|
||||
description: |
|
||||
After submitting this, I commit to one of:
|
||||
|
||||
* Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.
|
||||
* Read open questions until I find 2 where I can help someone and add a comment to help there.
|
||||
* I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.
|
||||
* Implement a Pull Request for a confirmed bug.
|
||||
* Review one Pull Request by downloading the code and following [all the review process](https://fastapi.tiangolo.com/help-fastapi/#review-pull-requests).
|
||||
|
||||
options:
|
||||
- label: I commit to help with one of those options 👆
|
||||
12
.github/ISSUE_TEMPLATE/config.yml
vendored
12
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -2,3 +2,15 @@ blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Security Contact
|
||||
about: Please report security vulnerabilities to security@tiangolo.com
|
||||
- name: Question or Problem
|
||||
about: Ask a question or ask about a problem in GitHub Discussions.
|
||||
url: https://github.com/tiangolo/fastapi/discussions/categories/questions
|
||||
- name: Feature Request
|
||||
about: To suggest an idea or ask about a feature, please start with a question saying what you would like to achieve. There might be a way to do it already.
|
||||
url: https://github.com/tiangolo/fastapi/discussions/categories/questions
|
||||
- name: Show and tell
|
||||
about: Show what you built with FastAPI or to be used with FastAPI.
|
||||
url: https://github.com/tiangolo/fastapi/discussions/categories/show-and-tell
|
||||
- name: Translations
|
||||
about: Coordinate translations in GitHub Discussions.
|
||||
url: https://github.com/tiangolo/fastapi/discussions/categories/translations
|
||||
|
||||
181
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
181
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
@@ -1,181 +0,0 @@
|
||||
name: Feature Request
|
||||
description: Suggest an idea or ask for a feature that you would like to have in FastAPI
|
||||
labels: [enhancement]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for your interest in FastAPI! 🚀
|
||||
|
||||
Please follow these instructions, fill every question, and do every step. 🙏
|
||||
|
||||
I'm asking this because answering questions and solving problems in GitHub issues is what consumes most of the time.
|
||||
|
||||
I end up not being able to add new features, fix bugs, review pull requests, etc. as fast as I wish because I have to spend too much time handling issues.
|
||||
|
||||
All that, on top of all the incredible help provided by a bunch of community members, the [FastAPI Experts](https://fastapi.tiangolo.com/fastapi-people/#experts), that give a lot of their time to come here and help others.
|
||||
|
||||
That's a lot of work they are doing, but if more FastAPI users came to help others like them just a little bit more, it would be much less effort for them (and you and me 😅).
|
||||
|
||||
By asking questions in a structured way (following this) it will be much easier to help you.
|
||||
|
||||
And there's a high chance that you will find the solution along the way and you won't even have to submit it and wait for an answer. 😎
|
||||
|
||||
As there are too many issues with questions, I'll have to close the incomplete ones. That will allow me (and others) to focus on helping people like you that follow the whole process and help us help you. 🤓
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: First Check
|
||||
description: Please confirm and check all the following options.
|
||||
options:
|
||||
- label: I added a very descriptive title to this issue.
|
||||
required: true
|
||||
- label: I used the GitHub search to find a similar issue and didn't find it.
|
||||
required: true
|
||||
- label: I searched the FastAPI documentation, with the integrated search.
|
||||
required: true
|
||||
- label: I already searched in Google "How to X in FastAPI" and didn't find any information.
|
||||
required: true
|
||||
- label: I already read and followed all the tutorial in the docs and didn't find an answer.
|
||||
required: true
|
||||
- label: I already checked if it is not related to FastAPI but to [Pydantic](https://github.com/samuelcolvin/pydantic).
|
||||
required: true
|
||||
- label: I already checked if it is not related to FastAPI but to [Swagger UI](https://github.com/swagger-api/swagger-ui).
|
||||
required: true
|
||||
- label: I already checked if it is not related to FastAPI but to [ReDoc](https://github.com/Redocly/redoc).
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: help
|
||||
attributes:
|
||||
label: Commit to Help
|
||||
description: |
|
||||
After submitting this, I commit to one of:
|
||||
|
||||
* Read open issues with questions until I find 2 issues where I can help someone and add a comment to help there.
|
||||
* I already hit the "watch" button in this repository to receive notifications and I commit to help at least 2 people that ask questions in the future.
|
||||
* Implement a Pull Request for a confirmed bug.
|
||||
|
||||
options:
|
||||
- label: I commit to help with one of those options 👆
|
||||
required: true
|
||||
- type: textarea
|
||||
id: example
|
||||
attributes:
|
||||
label: Example Code
|
||||
description: |
|
||||
Please add a self-contained, [minimal, reproducible, example](https://stackoverflow.com/help/minimal-reproducible-example) with your use case.
|
||||
|
||||
If I (or someone) can copy it, run it, and see it right away, there's a much higher chance I (or someone) will be able to help you.
|
||||
|
||||
placeholder: |
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
render: python
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: |
|
||||
What is your feature request?
|
||||
|
||||
Write a short description telling me what you are trying to solve and what you are currently doing.
|
||||
placeholder: |
|
||||
* Open the browser and call the endpoint `/`.
|
||||
* It returns a JSON with `{"Hello": "World"}`.
|
||||
* I would like it to have an extra parameter to teleport me to the moon and back.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: wanted-solution
|
||||
attributes:
|
||||
label: Wanted Solution
|
||||
description: |
|
||||
Tell me what's the solution you would like.
|
||||
placeholder: |
|
||||
I would like it to have a `teleport_to_moon` parameter that defaults to `False`, and can be set to `True` to teleport me.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: wanted-code
|
||||
attributes:
|
||||
label: Wanted Code
|
||||
description: Show me an example of how you would want the code to look like.
|
||||
placeholder: |
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/", teleport_to_moon=True)
|
||||
def read_root():
|
||||
return {"Hello": "World"}
|
||||
render: python
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Alternatives
|
||||
description: |
|
||||
Tell me about alternatives you've considered.
|
||||
placeholder: |
|
||||
To wait for Space X moon travel plans to drop down long after they release them. But I would rather teleport.
|
||||
- type: dropdown
|
||||
id: os
|
||||
attributes:
|
||||
label: Operating System
|
||||
description: What operating system are you on?
|
||||
multiple: true
|
||||
options:
|
||||
- Linux
|
||||
- Windows
|
||||
- macOS
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: os-details
|
||||
attributes:
|
||||
label: Operating System Details
|
||||
description: You can add more details about your operating system here, in particular if you chose "Other".
|
||||
- type: input
|
||||
id: fastapi-version
|
||||
attributes:
|
||||
label: FastAPI Version
|
||||
description: |
|
||||
What FastAPI version are you using?
|
||||
|
||||
You can find the FastAPI version with:
|
||||
|
||||
```bash
|
||||
python -c "import fastapi; print(fastapi.__version__)"
|
||||
```
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: python-version
|
||||
attributes:
|
||||
label: Python Version
|
||||
description: |
|
||||
What Python version are you using?
|
||||
|
||||
You can find the Python version with:
|
||||
|
||||
```bash
|
||||
python --version
|
||||
```
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Add any additional context information or screenshots you think are useful.
|
||||
22
.github/ISSUE_TEMPLATE/privileged.yml
vendored
Normal file
22
.github/ISSUE_TEMPLATE/privileged.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Privileged
|
||||
description: You are @tiangolo or he asked you directly to create an issue here. If not, check the other options. 👇
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for your interest in FastAPI! 🚀
|
||||
|
||||
If you are not @tiangolo or he didn't ask you directly to create an issue here, please start the conversation in a [Question in GitHub Discussions](https://github.com/tiangolo/fastapi/discussions/categories/questions) instead.
|
||||
- type: checkboxes
|
||||
id: privileged
|
||||
attributes:
|
||||
label: Privileged issue
|
||||
description: Confirm that you are allowed to create an issue here.
|
||||
options:
|
||||
- label: I'm @tiangolo or he asked me directly to create an issue here.
|
||||
required: true
|
||||
- type: textarea
|
||||
id: content
|
||||
attributes:
|
||||
label: Issue Content
|
||||
description: Add the content of the issue here.
|
||||
206
.github/actions/people/app/main.py
vendored
206
.github/actions/people/app/main.py
vendored
@@ -4,7 +4,7 @@ import sys
|
||||
from collections import Counter, defaultdict
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
from typing import Container, DefaultDict, Dict, List, Set, Union
|
||||
from typing import Any, Container, DefaultDict, Dict, List, Set, Union
|
||||
|
||||
import httpx
|
||||
import yaml
|
||||
@@ -12,6 +12,50 @@ from github import Github
|
||||
from pydantic import BaseModel, BaseSettings, SecretStr
|
||||
|
||||
github_graphql_url = "https://api.github.com/graphql"
|
||||
questions_category_id = "MDE4OkRpc2N1c3Npb25DYXRlZ29yeTMyMDAxNDM0"
|
||||
|
||||
discussions_query = """
|
||||
query Q($after: String, $category_id: ID) {
|
||||
repository(name: "fastapi", owner: "tiangolo") {
|
||||
discussions(first: 100, after: $after, categoryId: $category_id) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
number
|
||||
author {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
title
|
||||
createdAt
|
||||
comments(first: 100) {
|
||||
nodes {
|
||||
createdAt
|
||||
author {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
isAnswer
|
||||
replies(first: 10) {
|
||||
nodes {
|
||||
createdAt
|
||||
author {
|
||||
login
|
||||
avatarUrl
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
issues_query = """
|
||||
query Q($after: String) {
|
||||
@@ -131,15 +175,30 @@ class Author(BaseModel):
|
||||
url: str
|
||||
|
||||
|
||||
# Issues and Discussions
|
||||
|
||||
|
||||
class CommentsNode(BaseModel):
|
||||
createdAt: datetime
|
||||
author: Union[Author, None] = None
|
||||
|
||||
|
||||
class Replies(BaseModel):
|
||||
nodes: List[CommentsNode]
|
||||
|
||||
|
||||
class DiscussionsCommentsNode(CommentsNode):
|
||||
replies: Replies
|
||||
|
||||
|
||||
class Comments(BaseModel):
|
||||
nodes: List[CommentsNode]
|
||||
|
||||
|
||||
class DiscussionsComments(BaseModel):
|
||||
nodes: List[DiscussionsCommentsNode]
|
||||
|
||||
|
||||
class IssuesNode(BaseModel):
|
||||
number: int
|
||||
author: Union[Author, None] = None
|
||||
@@ -149,27 +208,59 @@ class IssuesNode(BaseModel):
|
||||
comments: Comments
|
||||
|
||||
|
||||
class DiscussionsNode(BaseModel):
|
||||
number: int
|
||||
author: Union[Author, None] = None
|
||||
title: str
|
||||
createdAt: datetime
|
||||
comments: DiscussionsComments
|
||||
|
||||
|
||||
class IssuesEdge(BaseModel):
|
||||
cursor: str
|
||||
node: IssuesNode
|
||||
|
||||
|
||||
class DiscussionsEdge(BaseModel):
|
||||
cursor: str
|
||||
node: DiscussionsNode
|
||||
|
||||
|
||||
class Issues(BaseModel):
|
||||
edges: List[IssuesEdge]
|
||||
|
||||
|
||||
class Discussions(BaseModel):
|
||||
edges: List[DiscussionsEdge]
|
||||
|
||||
|
||||
class IssuesRepository(BaseModel):
|
||||
issues: Issues
|
||||
|
||||
|
||||
class DiscussionsRepository(BaseModel):
|
||||
discussions: Discussions
|
||||
|
||||
|
||||
class IssuesResponseData(BaseModel):
|
||||
repository: IssuesRepository
|
||||
|
||||
|
||||
class DiscussionsResponseData(BaseModel):
|
||||
repository: DiscussionsRepository
|
||||
|
||||
|
||||
class IssuesResponse(BaseModel):
|
||||
data: IssuesResponseData
|
||||
|
||||
|
||||
class DiscussionsResponse(BaseModel):
|
||||
data: DiscussionsResponseData
|
||||
|
||||
|
||||
# PRs
|
||||
|
||||
|
||||
class LabelNode(BaseModel):
|
||||
name: str
|
||||
|
||||
@@ -219,6 +310,9 @@ class PRsResponse(BaseModel):
|
||||
data: PRsResponseData
|
||||
|
||||
|
||||
# Sponsors
|
||||
|
||||
|
||||
class SponsorEntity(BaseModel):
|
||||
login: str
|
||||
avatarUrl: str
|
||||
@@ -264,10 +358,16 @@ class Settings(BaseSettings):
|
||||
|
||||
|
||||
def get_graphql_response(
|
||||
*, settings: Settings, query: str, after: Union[str, None] = None
|
||||
):
|
||||
*,
|
||||
settings: Settings,
|
||||
query: str,
|
||||
after: Union[str, None] = None,
|
||||
category_id: Union[str, None] = None,
|
||||
) -> Dict[str, Any]:
|
||||
headers = {"Authorization": f"token {settings.input_token.get_secret_value()}"}
|
||||
variables = {"after": after}
|
||||
# category_id is only used by one query, but GraphQL allows unused variables, so
|
||||
# keep it here for simplicity
|
||||
variables = {"after": after, "category_id": category_id}
|
||||
response = httpx.post(
|
||||
github_graphql_url,
|
||||
headers=headers,
|
||||
@@ -275,7 +375,9 @@ def get_graphql_response(
|
||||
json={"query": query, "variables": variables, "operationName": "Q"},
|
||||
)
|
||||
if response.status_code != 200:
|
||||
logging.error(f"Response was not 200, after: {after}")
|
||||
logging.error(
|
||||
f"Response was not 200, after: {after}, category_id: {category_id}"
|
||||
)
|
||||
logging.error(response.text)
|
||||
raise RuntimeError(response.text)
|
||||
data = response.json()
|
||||
@@ -288,6 +390,21 @@ def get_graphql_issue_edges(*, settings: Settings, after: Union[str, None] = Non
|
||||
return graphql_response.data.repository.issues.edges
|
||||
|
||||
|
||||
def get_graphql_question_discussion_edges(
|
||||
*,
|
||||
settings: Settings,
|
||||
after: Union[str, None] = None,
|
||||
):
|
||||
data = get_graphql_response(
|
||||
settings=settings,
|
||||
query=discussions_query,
|
||||
after=after,
|
||||
category_id=questions_category_id,
|
||||
)
|
||||
graphql_response = DiscussionsResponse.parse_obj(data)
|
||||
return graphql_response.data.repository.discussions.edges
|
||||
|
||||
|
||||
def get_graphql_pr_edges(*, settings: Settings, after: Union[str, None] = None):
|
||||
data = get_graphql_response(settings=settings, query=prs_query, after=after)
|
||||
graphql_response = PRsResponse.parse_obj(data)
|
||||
@@ -300,7 +417,7 @@ def get_graphql_sponsor_edges(*, settings: Settings, after: Union[str, None] = N
|
||||
return graphql_response.data.user.sponsorshipsAsMaintainer.edges
|
||||
|
||||
|
||||
def get_experts(settings: Settings):
|
||||
def get_issues_experts(settings: Settings):
|
||||
issue_nodes: List[IssuesNode] = []
|
||||
issue_edges = get_graphql_issue_edges(settings=settings)
|
||||
|
||||
@@ -326,13 +443,74 @@ def get_experts(settings: Settings):
|
||||
for comment in issue.comments.nodes:
|
||||
if comment.author:
|
||||
authors[comment.author.login] = comment.author
|
||||
if comment.author.login == issue_author_name:
|
||||
continue
|
||||
issue_commentors.add(comment.author.login)
|
||||
if comment.author.login != issue_author_name:
|
||||
issue_commentors.add(comment.author.login)
|
||||
for author_name in issue_commentors:
|
||||
commentors[author_name] += 1
|
||||
if issue.createdAt > one_month_ago:
|
||||
last_month_commentors[author_name] += 1
|
||||
|
||||
return commentors, last_month_commentors, authors
|
||||
|
||||
|
||||
def get_discussions_experts(settings: Settings):
|
||||
discussion_nodes: List[DiscussionsNode] = []
|
||||
discussion_edges = get_graphql_question_discussion_edges(settings=settings)
|
||||
|
||||
while discussion_edges:
|
||||
for discussion_edge in discussion_edges:
|
||||
discussion_nodes.append(discussion_edge.node)
|
||||
last_edge = discussion_edges[-1]
|
||||
discussion_edges = get_graphql_question_discussion_edges(
|
||||
settings=settings, after=last_edge.cursor
|
||||
)
|
||||
|
||||
commentors = Counter()
|
||||
last_month_commentors = Counter()
|
||||
authors: Dict[str, Author] = {}
|
||||
|
||||
now = datetime.now(tz=timezone.utc)
|
||||
one_month_ago = now - timedelta(days=30)
|
||||
|
||||
for discussion in discussion_nodes:
|
||||
discussion_author_name = None
|
||||
if discussion.author:
|
||||
authors[discussion.author.login] = discussion.author
|
||||
discussion_author_name = discussion.author.login
|
||||
discussion_commentors = set()
|
||||
for comment in discussion.comments.nodes:
|
||||
if comment.author:
|
||||
authors[comment.author.login] = comment.author
|
||||
if comment.author.login != discussion_author_name:
|
||||
discussion_commentors.add(comment.author.login)
|
||||
for reply in comment.replies.nodes:
|
||||
if reply.author:
|
||||
authors[reply.author.login] = reply.author
|
||||
if reply.author.login != discussion_author_name:
|
||||
discussion_commentors.add(reply.author.login)
|
||||
for author_name in discussion_commentors:
|
||||
commentors[author_name] += 1
|
||||
if discussion.createdAt > one_month_ago:
|
||||
last_month_commentors[author_name] += 1
|
||||
return commentors, last_month_commentors, authors
|
||||
|
||||
|
||||
def get_experts(settings: Settings):
|
||||
(
|
||||
issues_commentors,
|
||||
issues_last_month_commentors,
|
||||
issues_authors,
|
||||
) = get_issues_experts(settings=settings)
|
||||
(
|
||||
discussions_commentors,
|
||||
discussions_last_month_commentors,
|
||||
discussions_authors,
|
||||
) = get_discussions_experts(settings=settings)
|
||||
commentors = issues_commentors + discussions_commentors
|
||||
last_month_commentors = (
|
||||
issues_last_month_commentors + discussions_last_month_commentors
|
||||
)
|
||||
authors = {**issues_authors, **discussions_authors}
|
||||
return commentors, last_month_commentors, authors
|
||||
|
||||
|
||||
@@ -425,13 +603,13 @@ if __name__ == "__main__":
|
||||
logging.info(f"Using config: {settings.json()}")
|
||||
g = Github(settings.input_standard_token.get_secret_value())
|
||||
repo = g.get_repo(settings.github_repository)
|
||||
issue_commentors, issue_last_month_commentors, issue_authors = get_experts(
|
||||
question_commentors, question_last_month_commentors, question_authors = get_experts(
|
||||
settings=settings
|
||||
)
|
||||
contributors, pr_commentors, reviewers, pr_authors = get_contributors(
|
||||
settings=settings
|
||||
)
|
||||
authors = {**issue_authors, **pr_authors}
|
||||
authors = {**question_authors, **pr_authors}
|
||||
maintainers_logins = {"tiangolo"}
|
||||
bot_names = {"codecov", "github-actions", "pre-commit-ci", "dependabot"}
|
||||
maintainers = []
|
||||
@@ -440,7 +618,7 @@ if __name__ == "__main__":
|
||||
maintainers.append(
|
||||
{
|
||||
"login": login,
|
||||
"answers": issue_commentors[login],
|
||||
"answers": question_commentors[login],
|
||||
"prs": contributors[login],
|
||||
"avatarUrl": user.avatarUrl,
|
||||
"url": user.url,
|
||||
@@ -453,13 +631,13 @@ if __name__ == "__main__":
|
||||
min_count_reviewer = 4
|
||||
skip_users = maintainers_logins | bot_names
|
||||
experts = get_top_users(
|
||||
counter=issue_commentors,
|
||||
counter=question_commentors,
|
||||
min_count=min_count_expert,
|
||||
authors=authors,
|
||||
skip_users=skip_users,
|
||||
)
|
||||
last_month_active = get_top_users(
|
||||
counter=issue_last_month_commentors,
|
||||
counter=question_last_month_commentors,
|
||||
min_count=min_count_last_month,
|
||||
authors=authors,
|
||||
skip_users=skip_users,
|
||||
|
||||
4
.github/workflows/build-docs.yml
vendored
4
.github/workflows/build-docs.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
types: [opened, synchronize]
|
||||
jobs:
|
||||
build-docs:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.7"
|
||||
python-version: "3.11"
|
||||
- uses: actions/cache@v3
|
||||
id: cache
|
||||
with:
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# See https://pre-commit.com for more information
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
default_language_version:
|
||||
python: python3.10
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.3.0
|
||||
@@ -25,7 +27,7 @@ repos:
|
||||
args:
|
||||
- --fix
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.10.1
|
||||
rev: 5.12.0
|
||||
hooks:
|
||||
- id: isort
|
||||
name: isort (python)
|
||||
|
||||
@@ -55,7 +55,7 @@ The key features are:
|
||||
<a href="https://testdriven.io/courses/tdd-fastapi/" target="_blank" title="Learn to build high-quality web apps with best practices"><img src="https://fastapi.tiangolo.com/img/sponsors/testdriven.svg"></a>
|
||||
<a href="https://github.com/deepset-ai/haystack/" target="_blank" title="Build powerful search from composable, open source building blocks"><img src="https://fastapi.tiangolo.com/img/sponsors/haystack-fastapi.svg"></a>
|
||||
<a href="https://www.udemy.com/course/fastapi-rest/" target="_blank" title="Learn FastAPI by building a complete project. Extend your knowledge on advanced web development-AWS, Payments, Emails."><img src="https://fastapi.tiangolo.com/img/sponsors/ines-course.jpg"></a>
|
||||
<a href="https://careers.budget-insight.com/" target="_blank" title="Budget Insight is hiring!"><img src="https://fastapi.tiangolo.com/img/sponsors/budget-insight.svg"></a>
|
||||
<a href="https://careers.powens.com/" target="_blank" title="Powens is hiring!"><img src="https://fastapi.tiangolo.com/img/sponsors/powens.png"></a>
|
||||
<a href="https://www.svix.com/" target="_blank" title="Svix - Webhooks as a service"><img src="https://fastapi.tiangolo.com/img/sponsors/svix.svg"></a>
|
||||
|
||||
<!-- /sponsors -->
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
articles:
|
||||
english:
|
||||
- author: Raf Rasenberg
|
||||
author_link: https://rafrasenberg.com/about/
|
||||
link: https://rafrasenberg.com/fastapi-lambda/
|
||||
title: 'FastAPI lambda container: serverless simplified'
|
||||
- author: Teresa N. Fontanella De Santis
|
||||
author_link: https://dev.to/
|
||||
link: https://dev.to/teresafds/authorization-on-fastapi-with-casbin-41og
|
||||
@@ -304,6 +308,11 @@ articles:
|
||||
author_link: https://fullstackstation.com/author/figonking/
|
||||
link: https://fullstackstation.com/fastapi-trien-khai-bang-docker/
|
||||
title: 'FASTAPI: TRIỂN KHAI BẰNG DOCKER'
|
||||
taiwanese:
|
||||
- author: Leon
|
||||
author_link: http://editor.leonh.space/
|
||||
link: https://editor.leonh.space/2022/tortoise/
|
||||
title: 'Tortoise ORM / FastAPI 整合快速筆記'
|
||||
podcasts:
|
||||
english:
|
||||
- author: Podcast.`__init__`
|
||||
|
||||
@@ -38,9 +38,6 @@ sponsors:
|
||||
- - login: vyos
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5647000?v=4
|
||||
url: https://github.com/vyos
|
||||
- login: SendCloud
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7831959?v=4
|
||||
url: https://github.com/SendCloud
|
||||
- login: takashi-yoneya
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/33813153?u=2d0522bceba0b8b69adf1f2db866503bd96f944e&v=4
|
||||
url: https://github.com/takashi-yoneya
|
||||
@@ -56,9 +53,6 @@ sponsors:
|
||||
- login: BoostryJP
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4
|
||||
url: https://github.com/BoostryJP
|
||||
- - login: InesIvanova
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/22920417?u=409882ec1df6dbd77455788bb383a8de223dbf6f&v=4
|
||||
url: https://github.com/InesIvanova
|
||||
- - login: johnadjei
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/767860?v=4
|
||||
url: https://github.com/johnadjei
|
||||
@@ -71,12 +65,12 @@ sponsors:
|
||||
- login: Lovage-Labs
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/71685552?v=4
|
||||
url: https://github.com/Lovage-Labs
|
||||
- - login: xshapira
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/48856190?u=3b0927ad29addab29a43767b52e45bee5cd6da9f&v=4
|
||||
url: https://github.com/xshapira
|
||||
- - login: moellenbeck
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/169372?v=4
|
||||
url: https://github.com/moellenbeck
|
||||
- login: birkjernstrom
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/281715?u=4be14b43f76b4bd497b1941309bb390250b405e6&v=4
|
||||
url: https://github.com/birkjernstrom
|
||||
- login: AccentDesign
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2429332?v=4
|
||||
url: https://github.com/AccentDesign
|
||||
@@ -89,9 +83,6 @@ sponsors:
|
||||
- login: dorianturba
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9381120?u=4bfc7032a824d1ed1994aa8256dfa597c8f187ad&v=4
|
||||
url: https://github.com/dorianturba
|
||||
- login: Qazzquimby
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/12368310?u=f4ed4a7167fd359cfe4502d56d7c64f9bf59bb38&v=4
|
||||
url: https://github.com/Qazzquimby
|
||||
- login: jmaralc
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/21101214?u=b15a9f07b7cbf6c9dcdbcb6550bbd2c52f55aa50&v=4
|
||||
url: https://github.com/jmaralc
|
||||
@@ -104,15 +95,9 @@ sponsors:
|
||||
- login: primer-io
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4
|
||||
url: https://github.com/primer-io
|
||||
- - login: guivaloz
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1296621?u=bc4fc28f96c654aa2be7be051d03a315951e2491&v=4
|
||||
url: https://github.com/guivaloz
|
||||
- login: indeedeng
|
||||
- - login: indeedeng
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2905043?v=4
|
||||
url: https://github.com/indeedeng
|
||||
- login: fratambot
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/20300069?u=41c85ea08960c8a8f0ce967b780e242b1454690c&v=4
|
||||
url: https://github.com/fratambot
|
||||
- - login: Kludex
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
|
||||
url: https://github.com/Kludex
|
||||
@@ -167,15 +152,15 @@ sponsors:
|
||||
- login: coffeewasmyidea
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1636488?u=8e32a4f200eff54dd79cd79d55d254bfce5e946d&v=4
|
||||
url: https://github.com/coffeewasmyidea
|
||||
- login: jonakoudijs
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1906344?u=5ca0c9a1a89b6a2ba31abe35c66bdc07af60a632&v=4
|
||||
url: https://github.com/jonakoudijs
|
||||
- login: corleyma
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2080732?u=aed2ff652294a87d666b1c3f6dbe98104db76d26&v=4
|
||||
url: https://github.com/corleyma
|
||||
- login: madisonmay
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2645393?u=f22b93c6ea345a4d26a90a3834dfc7f0789fcb63&v=4
|
||||
url: https://github.com/madisonmay
|
||||
- login: saivarunk
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2976867?u=71f4385e781e9a9e871a52f2d4686f9a8d69ba2f&v=4
|
||||
url: https://github.com/saivarunk
|
||||
- login: andre1sk
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3148093?v=4
|
||||
url: https://github.com/andre1sk
|
||||
@@ -191,9 +176,6 @@ sponsors:
|
||||
- login: zsinx6
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3532625?u=ba75a5dc744d1116ccfeaaf30d41cb2fe81fe8dd&v=4
|
||||
url: https://github.com/zsinx6
|
||||
- login: MarekBleschke
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3616870?v=4
|
||||
url: https://github.com/MarekBleschke
|
||||
- login: aacayaco
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3634801?u=eaadda178c964178fcb64886f6c732172c8f8219&v=4
|
||||
url: https://github.com/aacayaco
|
||||
@@ -239,6 +221,9 @@ sponsors:
|
||||
- login: Rehket
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7015688?u=3afb0ba200feebbc7f958950e92db34df2a3c172&v=4
|
||||
url: https://github.com/Rehket
|
||||
- login: ValentinCalomme
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7288672?u=e09758c7a36c49f0fb3574abe919cbd344fdc2d6&v=4
|
||||
url: https://github.com/ValentinCalomme
|
||||
- login: hiancdtrsnm
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7343177?v=4
|
||||
url: https://github.com/hiancdtrsnm
|
||||
@@ -248,15 +233,9 @@ sponsors:
|
||||
- login: wdwinslow
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4
|
||||
url: https://github.com/wdwinslow
|
||||
- login: jacobkrit
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11823915?u=4921a7ea429b7eadcad3077f119f90d15a3318b2&v=4
|
||||
url: https://github.com/jacobkrit
|
||||
- login: svats2k
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/12378398?u=ecf28c19f61052e664bdfeb2391f8107d137915c&v=4
|
||||
url: https://github.com/svats2k
|
||||
- login: gokulyc
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/13468848?u=269f269d3e70407b5fb80138c52daba7af783997&v=4
|
||||
url: https://github.com/gokulyc
|
||||
- login: dannywade
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/13680237?u=418ee985bd41577b20fde81417fb2d901e875e8a&v=4
|
||||
url: https://github.com/dannywade
|
||||
@@ -305,6 +284,9 @@ sponsors:
|
||||
- login: ProteinQure
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/33707203?v=4
|
||||
url: https://github.com/ProteinQure
|
||||
- login: AbdulwahabDev
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/34792253?u=9d27cbb6e196c95d747abf002df7fe0539764265&v=4
|
||||
url: https://github.com/AbdulwahabDev
|
||||
- login: ybressler
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/40807730?u=41e2c00f1eebe3c402635f0325e41b4e6511462c&v=4
|
||||
url: https://github.com/ybressler
|
||||
@@ -314,18 +296,15 @@ sponsors:
|
||||
- login: VictorCalderon
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/44529243?u=cea69884f826a29aff1415493405209e0706d07a&v=4
|
||||
url: https://github.com/VictorCalderon
|
||||
- login: arthuRHD
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/48015496?u=05a0d5b8b9320eeb7990d35c9337b823f269d2ff&v=4
|
||||
url: https://github.com/arthuRHD
|
||||
- login: rafsaf
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
|
||||
url: https://github.com/rafsaf
|
||||
- login: dudikbender
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=494f85229115076121b3639a3806bbac1c6ae7f6&v=4
|
||||
url: https://github.com/dudikbender
|
||||
- login: dazeddd
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/59472056?u=7a1b668449bf8b448db13e4c575576d24d7d658b&v=4
|
||||
url: https://github.com/dazeddd
|
||||
- login: thisistheplace
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/57633545?u=a3f3a7f8ace8511c6c067753f6eb6aee0db11ac6&v=4
|
||||
url: https://github.com/thisistheplace
|
||||
- login: A-Edge
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/59514131?v=4
|
||||
url: https://github.com/A-Edge
|
||||
@@ -425,9 +404,6 @@ sponsors:
|
||||
- login: paul121
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3116995?u=6e2d8691cc345e63ee02e4eb4d7cef82b1fcbedc&v=4
|
||||
url: https://github.com/paul121
|
||||
- login: igorcorrea
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3438238?u=c57605077c31a8f7b2341fc4912507f91b4a5621&v=4
|
||||
url: https://github.com/igorcorrea
|
||||
- login: larsvik
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3442226?v=4
|
||||
url: https://github.com/larsvik
|
||||
@@ -497,6 +473,9 @@ sponsors:
|
||||
- login: logan-connolly
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16244943?u=8ae66dfbba936463cc8aa0dd7a6d2b4c0cc757eb&v=4
|
||||
url: https://github.com/logan-connolly
|
||||
- login: harripj
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16853829?u=14db1ad132af9ec340f3f1da564620a73b6e4981&v=4
|
||||
url: https://github.com/harripj
|
||||
- login: cdsre
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16945936?v=4
|
||||
url: https://github.com/cdsre
|
||||
@@ -516,11 +495,14 @@ sponsors:
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/24669867?u=60e7c8c09f8dafabee8fc3edcd6f9e19abbff918&v=4
|
||||
url: https://github.com/fstau
|
||||
- login: pers0n4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/24864600?u=7e5d2bf26d0a0670ea347f7db5febebc4e031ed1&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/24864600?u=f211a13a7b572cbbd7779b9c8d8cb428cc7ba07e&v=4
|
||||
url: https://github.com/pers0n4
|
||||
- login: SebTota
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/25122511?v=4
|
||||
url: https://github.com/SebTota
|
||||
- login: hoenie-ams
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/25708487?u=cda07434f0509ac728d9edf5e681117c0f6b818b&v=4
|
||||
url: https://github.com/hoenie-ams
|
||||
- login: joerambo
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/26282974?v=4
|
||||
url: https://github.com/joerambo
|
||||
@@ -537,7 +519,7 @@ sponsors:
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/33275230?u=eb223cad27017bb1e936ee9b429b450d092d0236&v=4
|
||||
url: https://github.com/engineerjoe440
|
||||
- login: bnkc
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=20f362505e2a994805233f42e69f9f14b4a9dd0c&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=76cdc0a8b4e88c7d3e58dccb4b2670839e1247b4&v=4
|
||||
url: https://github.com/bnkc
|
||||
- login: declon
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/36180226?v=4
|
||||
@@ -552,10 +534,10 @@ sponsors:
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/38921751?u=ae14bc1e40f2dd5a9c5741fc0b0dffbd416a5fa9&v=4
|
||||
url: https://github.com/ww-daniel-mora
|
||||
- login: rwxd
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=b3cb7a606207141c357e517071cf91a67fb5577e&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=34cba2eaca6a52072498e06bccebe141694fe1d7&v=4
|
||||
url: https://github.com/rwxd
|
||||
- login: ilias-ant
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a2d6121bac4d125d92ec207460fa3f1842d37e66&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/42189572?u=a84d169eb6f6bbcb85434c2bed0b4a6d4d13c10e&v=4
|
||||
url: https://github.com/ilias-ant
|
||||
- login: arrrrrmin
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43553423?u=2a812c1a2ec58227ed01778837f255143de9df97&v=4
|
||||
@@ -593,21 +575,24 @@ sponsors:
|
||||
- login: pondDevThai
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/71592181?u=08af9a59bccfd8f6b101de1005aa9822007d0a44&v=4
|
||||
url: https://github.com/pondDevThai
|
||||
- login: zeb0x01
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/77236545?u=c62bfcfbd463f9cf171c879cea1362a63de2c582&v=4
|
||||
url: https://github.com/zeb0x01
|
||||
- login: lironmiz
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/91504420?u=cb93dfec613911ac8d4e84fbb560711546711ad5&v=4
|
||||
url: https://github.com/lironmiz
|
||||
- - login: gabrielmbmb
|
||||
- login: lukzmu
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/80778518?u=f636ad03cab8e8de15183fa81e768bfad3f515d0&v=4
|
||||
url: https://github.com/lukzmu
|
||||
- - login: chrislemke
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11752694?u=70ceb6ee7c51d9a52302ab9220ffbf09eaa9c2a4&v=4
|
||||
url: https://github.com/chrislemke
|
||||
- login: gabrielmbmb
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/29572918?u=6d1e00b5d558e96718312ff910a2318f47cc3145&v=4
|
||||
url: https://github.com/gabrielmbmb
|
||||
- login: danburonline
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/34251194?u=2cad4388c1544e539ecb732d656e42fb07b4ff2d&v=4
|
||||
url: https://github.com/danburonline
|
||||
- login: Moises6669
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/66188523?u=96af25b8d5be9f983cb96e9dd7c605c716caf1f5&v=4
|
||||
url: https://github.com/Moises6669
|
||||
- login: lyuboparvanov
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/106192895?u=367329c777320e01550afda9d8de670436181d86&v=4
|
||||
url: https://github.com/lyuboparvanov
|
||||
- login: buabaj
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/49881677?u=a85952891036eb448f86eb847902f25badd5f9f7&v=4
|
||||
url: https://github.com/buabaj
|
||||
- login: SoulPancake
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/70265851?u=9cdd82f2835da7d6a56a2e29e1369d5bf251e8f2&v=4
|
||||
url: https://github.com/SoulPancake
|
||||
- login: junah201
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/75025529?u=2451c256e888fa2a06bcfc0646d09b87ddb6a945&v=4
|
||||
url: https://github.com/junah201
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
maintainers:
|
||||
- login: tiangolo
|
||||
answers: 1878
|
||||
prs: 361
|
||||
answers: 1956
|
||||
prs: 372
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=740f11212a731f56798f558ceddb0bd07642afa7&v=4
|
||||
url: https://github.com/tiangolo
|
||||
experts:
|
||||
- login: Kludex
|
||||
count: 379
|
||||
count: 400
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: dmontagu
|
||||
@@ -14,15 +14,15 @@ experts:
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
|
||||
url: https://github.com/dmontagu
|
||||
- login: ycd
|
||||
count: 221
|
||||
count: 224
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: Mause
|
||||
count: 207
|
||||
count: 223
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4
|
||||
url: https://github.com/Mause
|
||||
- login: JarroVGIT
|
||||
count: 192
|
||||
count: 196
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4
|
||||
url: https://github.com/JarroVGIT
|
||||
- login: euri10
|
||||
@@ -34,27 +34,31 @@ experts:
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4
|
||||
url: https://github.com/phy25
|
||||
- login: iudeen
|
||||
count: 103
|
||||
count: 118
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
|
||||
url: https://github.com/iudeen
|
||||
- login: jgould22
|
||||
count: 95
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
|
||||
url: https://github.com/jgould22
|
||||
- login: raphaelauv
|
||||
count: 77
|
||||
count: 79
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
|
||||
url: https://github.com/raphaelauv
|
||||
- login: ArcLightSlavik
|
||||
count: 71
|
||||
count: 74
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4
|
||||
url: https://github.com/ArcLightSlavik
|
||||
- login: jgould22
|
||||
count: 68
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
|
||||
url: https://github.com/jgould22
|
||||
- login: ghandic
|
||||
count: 72
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
|
||||
url: https://github.com/ghandic
|
||||
- login: falkben
|
||||
count: 59
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/653031?u=0c8d8f33d87f1aa1a6488d3f02105e9abc838105&v=4
|
||||
url: https://github.com/falkben
|
||||
- login: sm-Fifteen
|
||||
count: 50
|
||||
count: 52
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4
|
||||
url: https://github.com/sm-Fifteen
|
||||
- login: insomnes
|
||||
@@ -65,14 +69,26 @@ experts:
|
||||
count: 45
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4
|
||||
url: https://github.com/Dustyposa
|
||||
- login: acidjunk
|
||||
count: 44
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4
|
||||
url: https://github.com/acidjunk
|
||||
- login: adriangb
|
||||
count: 41
|
||||
count: 44
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=1e2c2c9b39f5c9b780fb933d8995cf08ec235a47&v=4
|
||||
url: https://github.com/adriangb
|
||||
- login: frankie567
|
||||
count: 41
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4
|
||||
url: https://github.com/frankie567
|
||||
- login: includeamin
|
||||
count: 39
|
||||
count: 40
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4
|
||||
url: https://github.com/includeamin
|
||||
- login: odiseo0
|
||||
count: 40
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=16f9255804161c6ff3c8b7ef69848f0126bcd405&v=4
|
||||
url: https://github.com/odiseo0
|
||||
- login: STeveShary
|
||||
count: 37
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4
|
||||
@@ -81,50 +97,34 @@ experts:
|
||||
count: 36
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4
|
||||
url: https://github.com/chbndrhnns
|
||||
- login: frankie567
|
||||
count: 34
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=85c025e3fcc7bd79a5665c63ee87cdf8aae13374&v=4
|
||||
url: https://github.com/frankie567
|
||||
- login: krishnardt
|
||||
count: 35
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4
|
||||
url: https://github.com/krishnardt
|
||||
- login: prostomarkeloff
|
||||
count: 33
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=72309cc1f2e04e40fa38b29969cb4e9d3f722e7b&v=4
|
||||
url: https://github.com/prostomarkeloff
|
||||
- login: acidjunk
|
||||
count: 32
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4
|
||||
url: https://github.com/acidjunk
|
||||
- login: krishnardt
|
||||
count: 31
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4
|
||||
url: https://github.com/krishnardt
|
||||
- login: yinziyan1206
|
||||
count: 33
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4
|
||||
url: https://github.com/yinziyan1206
|
||||
- login: panla
|
||||
count: 30
|
||||
count: 32
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/41326348?u=ba2fda6b30110411ecbf406d187907e2b420ac19&v=4
|
||||
url: https://github.com/panla
|
||||
- login: wshayes
|
||||
count: 29
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4
|
||||
url: https://github.com/wshayes
|
||||
- login: ghandic
|
||||
count: 25
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4
|
||||
url: https://github.com/ghandic
|
||||
- login: dbanty
|
||||
count: 25
|
||||
count: 26
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9bcce836bbce55835291c5b2ac93a4e311f4b3c3&v=4
|
||||
url: https://github.com/dbanty
|
||||
- login: yinziyan1206
|
||||
count: 25
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4
|
||||
url: https://github.com/yinziyan1206
|
||||
- login: SirTelemak
|
||||
count: 24
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9435877?u=719327b7d2c4c62212456d771bfa7c6b8dbb9eac&v=4
|
||||
url: https://github.com/SirTelemak
|
||||
- login: odiseo0
|
||||
count: 24
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=16f9255804161c6ff3c8b7ef69848f0126bcd405&v=4
|
||||
url: https://github.com/odiseo0
|
||||
- login: acnebs
|
||||
count: 22
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9054108?u=c27e50269f1ef8ea950cc6f0268c8ec5cebbe9c9&v=4
|
||||
@@ -137,18 +137,22 @@ experts:
|
||||
count: 21
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4
|
||||
url: https://github.com/chris-allnutt
|
||||
- login: rafsaf
|
||||
count: 21
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
|
||||
url: https://github.com/rafsaf
|
||||
- login: Hultner
|
||||
count: 19
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4
|
||||
url: https://github.com/Hultner
|
||||
- login: retnikt
|
||||
count: 19
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4
|
||||
url: https://github.com/retnikt
|
||||
- login: rafsaf
|
||||
count: 19
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=f8f0d6d6e90fac39fa786228158ba7f013c74271&v=4
|
||||
url: https://github.com/rafsaf
|
||||
- login: Hultner
|
||||
- login: zoliknemet
|
||||
count: 18
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4
|
||||
url: https://github.com/Hultner
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/22326718?u=31ba446ac290e23e56eea8e4f0c558aaf0b40779&v=4
|
||||
url: https://github.com/zoliknemet
|
||||
- login: jorgerpo
|
||||
count: 17
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4
|
||||
@@ -169,18 +173,22 @@ experts:
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4
|
||||
url: https://github.com/dstlny
|
||||
- login: jonatasoli
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4
|
||||
url: https://github.com/jonatasoli
|
||||
- login: hellocoldworld
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/47581948?u=3d2186796434c507a6cb6de35189ab0ad27c356f&v=4
|
||||
url: https://github.com/hellocoldworld
|
||||
- login: jonatasoli
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=071c062d2861d3dd127f6b4a5258cd8ef55d4c50&v=4
|
||||
url: https://github.com/jonatasoli
|
||||
- login: mbroton
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/50829834?u=a48610bf1bffaa9c75d03228926e2eb08a2e24ee&v=4
|
||||
url: https://github.com/mbroton
|
||||
- login: simondale00
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/33907262?v=4
|
||||
url: https://github.com/simondale00
|
||||
- login: haizaar
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/58201?u=dd40d99a3e1935d0b768f122bfe2258d6ea53b2b&v=4
|
||||
@@ -189,39 +197,43 @@ experts:
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4
|
||||
url: https://github.com/n8sty
|
||||
- login: valentin994
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/42819267?u=fdeeaa9242a59b243f8603496b00994f6951d5a2&v=4
|
||||
url: https://github.com/valentin994
|
||||
- login: David-Lor
|
||||
count: 12
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/17401854?u=474680c02b94cba810cb9032fb7eb787d9cc9d22&v=4
|
||||
url: https://github.com/David-Lor
|
||||
last_month_active:
|
||||
- login: iudeen
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
|
||||
url: https://github.com/iudeen
|
||||
- login: jgould22
|
||||
count: 13
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4
|
||||
url: https://github.com/jgould22
|
||||
- login: NewSouthMjos
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/77476573?v=4
|
||||
url: https://github.com/NewSouthMjos
|
||||
- login: davismartens
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/69799848?u=dbdfd256dd4e0a12d93efb3463225f3e39d8df6f&v=4
|
||||
url: https://github.com/davismartens
|
||||
- login: yinziyan1206
|
||||
count: 6
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4
|
||||
url: https://github.com/yinziyan1206
|
||||
- login: Kludex
|
||||
count: 3
|
||||
count: 6
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: Lenclove
|
||||
- login: moadennagi
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16942283?v=4
|
||||
url: https://github.com/moadennagi
|
||||
- login: iudeen
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
|
||||
url: https://github.com/iudeen
|
||||
- login: anthonycorletti
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3477132?v=4
|
||||
url: https://github.com/anthonycorletti
|
||||
- login: ThirVondukr
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/50728601?u=56010d6430583b2096a96f0946501156cdb79c75&v=4
|
||||
url: https://github.com/ThirVondukr
|
||||
- login: ebottos94
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/100039558?u=e2c672da5a7977fd24d87ce6ab35f8bf5b1ed9fa&v=4
|
||||
url: https://github.com/ebottos94
|
||||
- login: odiseo0
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/32355298?u=d0065e01650c63c2b2413f42d983634b2ea85481&v=4
|
||||
url: https://github.com/Lenclove
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=16f9255804161c6ff3c8b7ef69848f0126bcd405&v=4
|
||||
url: https://github.com/odiseo0
|
||||
top_contributors:
|
||||
- login: waynerv
|
||||
count: 25
|
||||
@@ -240,7 +252,7 @@ top_contributors:
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=58ed2a45798a4339700e2f62b2e12e6e54bf0396&v=4
|
||||
url: https://github.com/dmontagu
|
||||
- login: Kludex
|
||||
count: 15
|
||||
count: 16
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: euri10
|
||||
@@ -287,6 +299,10 @@ top_contributors:
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43503750?u=f440bc9062afb3c43b9b9c6cdfdcfe31d58699ef&v=4
|
||||
url: https://github.com/ComicShrimp
|
||||
- login: NinaHwang
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4
|
||||
url: https://github.com/NinaHwang
|
||||
- login: batlopes
|
||||
count: 5
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/33462923?u=0fb3d7acb316764616f11e4947faf080e49ad8d9&v=4
|
||||
@@ -319,13 +335,13 @@ top_contributors:
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
|
||||
url: https://github.com/lsglucas
|
||||
- login: NinaHwang
|
||||
- login: Xewus
|
||||
count: 4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4
|
||||
url: https://github.com/NinaHwang
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=4bdd4a0300530a504987db27488ba79c37f2fb18&v=4
|
||||
url: https://github.com/Xewus
|
||||
top_reviewers:
|
||||
- login: Kludex
|
||||
count: 109
|
||||
count: 110
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=62adc405ef418f4b6c8caa93d3eb8ab107bc4927&v=4
|
||||
url: https://github.com/Kludex
|
||||
- login: BilalAlpaslan
|
||||
@@ -333,7 +349,7 @@ top_reviewers:
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/47563997?u=63ed66e304fe8d765762c70587d61d9196e5c82d&v=4
|
||||
url: https://github.com/BilalAlpaslan
|
||||
- login: yezz123
|
||||
count: 66
|
||||
count: 70
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/52716203?u=636b4f79645176df4527dd45c12d5dbb5a4193cf&v=4
|
||||
url: https://github.com/yezz123
|
||||
- login: tokusumi
|
||||
@@ -353,7 +369,7 @@ top_reviewers:
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=bba5af018423a2858d49309bed2a899bb5c34ac5&v=4
|
||||
url: https://github.com/ycd
|
||||
- login: iudeen
|
||||
count: 42
|
||||
count: 44
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10519440?u=2843b3303282bff8b212dcd4d9d6689452e4470c&v=4
|
||||
url: https://github.com/iudeen
|
||||
- login: cikay
|
||||
@@ -372,14 +388,14 @@ top_reviewers:
|
||||
count: 31
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4
|
||||
url: https://github.com/ArcLightSlavik
|
||||
- login: cassiobotaro
|
||||
count: 28
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4
|
||||
url: https://github.com/cassiobotaro
|
||||
- login: komtaki
|
||||
count: 27
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/39375566?u=260ad6b1a4b34c07dbfa728da5e586f16f6d1824&v=4
|
||||
url: https://github.com/komtaki
|
||||
- login: cassiobotaro
|
||||
count: 26
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3127847?u=b0a652331da17efeb85cd6e3a4969182e5004804&v=4
|
||||
url: https://github.com/cassiobotaro
|
||||
- login: lsglucas
|
||||
count: 26
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/61513630?u=320e43fe4dc7bc6efc64e9b8f325f8075634fd20&v=4
|
||||
@@ -392,14 +408,22 @@ top_reviewers:
|
||||
count: 20
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4
|
||||
url: https://github.com/hard-coders
|
||||
- login: LorhanSohaky
|
||||
count: 19
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4
|
||||
url: https://github.com/LorhanSohaky
|
||||
- login: 0417taehyun
|
||||
count: 19
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/63915557?u=47debaa860fd52c9b98c97ef357ddcec3b3fb399&v=4
|
||||
url: https://github.com/0417taehyun
|
||||
- login: rjNemo
|
||||
count: 17
|
||||
count: 18
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/56785022?u=d5c3a02567c8649e146fcfc51b6060ccaf8adef8&v=4
|
||||
url: https://github.com/rjNemo
|
||||
- login: odiseo0
|
||||
count: 18
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=16f9255804161c6ff3c8b7ef69848f0126bcd405&v=4
|
||||
url: https://github.com/odiseo0
|
||||
- login: Smlep
|
||||
count: 17
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16785985?v=4
|
||||
@@ -428,10 +452,6 @@ top_reviewers:
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/63476957?u=6c86e59b48e0394d4db230f37fc9ad4d7e2c27c7&v=4
|
||||
url: https://github.com/delhi09
|
||||
- login: odiseo0
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=16f9255804161c6ff3c8b7ef69848f0126bcd405&v=4
|
||||
url: https://github.com/odiseo0
|
||||
- login: sh0nk
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6478810?u=af15d724875cec682ed8088a86d36b2798f981c0&v=4
|
||||
@@ -440,14 +460,18 @@ top_reviewers:
|
||||
count: 12
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/31848542?u=494ecc298e3f26197495bb357ad0f57cfd5f7a32&v=4
|
||||
url: https://github.com/RunningIkkyu
|
||||
- login: LorhanSohaky
|
||||
count: 11
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16273730?u=095b66f243a2cd6a0aadba9a095009f8aaf18393&v=4
|
||||
url: https://github.com/LorhanSohaky
|
||||
- login: Ryandaydev
|
||||
count: 12
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4292423?u=809f3d1074d04bbc28012a7f17f06ea56f5bd71a&v=4
|
||||
url: https://github.com/Ryandaydev
|
||||
- login: solomein-sv
|
||||
count: 11
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/46193920?u=46acfb4aeefb1d7b9fdc5a8cbd9eb8744683c47a&v=4
|
||||
url: https://github.com/solomein-sv
|
||||
- login: Xewus
|
||||
count: 11
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=4bdd4a0300530a504987db27488ba79c37f2fb18&v=4
|
||||
url: https://github.com/Xewus
|
||||
- login: mariacamilagl
|
||||
count: 10
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11489395?u=4adb6986bf3debfc2b8216ae701f2bd47d73da7d&v=4
|
||||
@@ -466,7 +490,7 @@ top_reviewers:
|
||||
url: https://github.com/ComicShrimp
|
||||
- login: peidrao
|
||||
count: 10
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/32584628?u=39edf7052371484cb488277638c23e1f6b584f4b&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/32584628?u=5401640e0b961cc199dee39ec79e162c7833cd6b&v=4
|
||||
url: https://github.com/peidrao
|
||||
- login: izaguerreiro
|
||||
count: 9
|
||||
@@ -496,6 +520,10 @@ top_reviewers:
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4
|
||||
url: https://github.com/raphaelauv
|
||||
- login: axel584
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1334088?v=4
|
||||
url: https://github.com/axel584
|
||||
- login: blt232018
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43393471?u=172b0e0391db1aa6c1706498d6dfcb003c8a4857&v=4
|
||||
@@ -508,15 +536,3 @@ top_reviewers:
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=1741703bd6c8f491503354b363a86e879b4c1cab&v=4
|
||||
url: https://github.com/NinaHwang
|
||||
- login: Xewus
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/85196001?u=4bdd4a0300530a504987db27488ba79c37f2fb18&v=4
|
||||
url: https://github.com/Xewus
|
||||
- login: Serrones
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/22691749?u=4795b880e13ca33a73e52fc0ef7dc9c60c8fce47&v=4
|
||||
url: https://github.com/Serrones
|
||||
- login: jovicon
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/21287303?u=b049eac3e51a4c0473c2efe66b4d28a7d8f2b572&v=4
|
||||
url: https://github.com/jovicon
|
||||
|
||||
@@ -27,9 +27,9 @@ silver:
|
||||
- url: https://www.udemy.com/course/fastapi-rest/
|
||||
title: Learn FastAPI by building a complete project. Extend your knowledge on advanced web development-AWS, Payments, Emails.
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/ines-course.jpg
|
||||
- url: https://careers.budget-insight.com/
|
||||
title: Budget Insight is hiring!
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/budget-insight.svg
|
||||
- url: https://careers.powens.com/
|
||||
title: Powens is hiring!
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/powens.png
|
||||
- url: https://www.svix.com/
|
||||
title: Svix - Webhooks as a service
|
||||
img: https://fastapi.tiangolo.com/img/sponsors/svix.svg
|
||||
|
||||
@@ -13,3 +13,5 @@ logins:
|
||||
- BLUE-DEVIL1134
|
||||
- ObliviousAI
|
||||
- Doist
|
||||
- nihpo
|
||||
- svix
|
||||
|
||||
@@ -56,6 +56,15 @@ Here's an incomplete list of some of them.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
### Taiwanese
|
||||
|
||||
{% if external_links %}
|
||||
{% for article in external_links.articles.taiwanese %}
|
||||
|
||||
* <a href="{{ article.link }}" class="external-link" target="_blank">{{ article.title }}</a> by <a href="{{ article.author_link }}" class="external-link" target="_blank">{{ article.author }}</a>.
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
## Podcasts
|
||||
|
||||
{% if external_links %}
|
||||
|
||||
@@ -28,7 +28,7 @@ I'm the creator and maintainer of **FastAPI**. You can read more about that in [
|
||||
|
||||
These are the people that:
|
||||
|
||||
* [Help others with issues (questions) in GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank}.
|
||||
* [Help others with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github){.internal-link target=_blank}.
|
||||
* [Create Pull Requests](help-fastapi.md#create-a-pull-request){.internal-link target=_blank}.
|
||||
* Review Pull Requests, [especially important for translations](contributing.md#translations){.internal-link target=_blank}.
|
||||
|
||||
@@ -36,13 +36,13 @@ A round of applause to them. 👏 🙇
|
||||
|
||||
## Most active users last month
|
||||
|
||||
These are the users that have been [helping others the most with issues (questions) in GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} during the last month. ☕
|
||||
These are the users that have been [helping others the most with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github){.internal-link target=_blank} during the last month. ☕
|
||||
|
||||
{% if people %}
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in people.last_month_active %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Issues replied: {{ user.count }}</div></div>
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Questions replied: {{ user.count }}</div></div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
@@ -52,7 +52,7 @@ These are the users that have been [helping others the most with issues (questio
|
||||
|
||||
Here are the **FastAPI Experts**. 🤓
|
||||
|
||||
These are the users that have [helped others the most with issues (questions) in GitHub](help-fastapi.md#help-others-with-issues-in-github){.internal-link target=_blank} through *all time*.
|
||||
These are the users that have [helped others the most with questions in GitHub](help-fastapi.md#help-others-with-questions-in-github){.internal-link target=_blank} through *all time*.
|
||||
|
||||
They have proven to be experts by helping many others. ✨
|
||||
|
||||
@@ -60,7 +60,7 @@ They have proven to be experts by helping many others. ✨
|
||||
<div class="user-list user-list-center">
|
||||
{% for user in people.experts %}
|
||||
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Issues replied: {{ user.count }}</div></div>
|
||||
<div class="user"><a href="{{ user.url }}" target="_blank"><div class="avatar-wrapper"><img src="{{ user.avatarUrl }}"/></div><div class="title">@{{ user.login }}</div></a> <div class="count">Questions replied: {{ user.count }}</div></div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
@@ -169,7 +169,7 @@ They are supporting my work with **FastAPI** (and others), mainly through <a hre
|
||||
|
||||
The main intention of this page is to highlight the effort of the community to help others.
|
||||
|
||||
Especially including efforts that are normally less visible, and in many cases more arduous, like helping others with issues and reviewing Pull Requests with translations.
|
||||
Especially including efforts that are normally less visible, and in many cases more arduous, like helping others with questions and reviewing Pull Requests with translations.
|
||||
|
||||
The data is calculated each month, you can read the <a href="https://github.com/tiangolo/fastapi/blob/master/.github/actions/people/app/main.py" class="external-link" target="_blank">source code here</a>.
|
||||
|
||||
|
||||
@@ -69,11 +69,16 @@ I love to hear about how **FastAPI** is being used, what you have liked in it, i
|
||||
* <a href="https://alternativeto.net/software/fastapi/" class="external-link" target="_blank">Vote for **FastAPI** in AlternativeTo</a>.
|
||||
* <a href="https://stackshare.io/pypi-fastapi" class="external-link" target="_blank">Say you use **FastAPI** on StackShare</a>.
|
||||
|
||||
## Help others with issues in GitHub
|
||||
## Help others with questions in GitHub
|
||||
|
||||
You can see <a href="https://github.com/tiangolo/fastapi/issues" class="external-link" target="_blank">existing issues</a> and try and help others, most of the times those issues are questions that you might already know the answer for. 🤓
|
||||
You can try and help others with their questions in:
|
||||
|
||||
If you are helping a lot of people with issues, you might become an official [FastAPI Expert](fastapi-people.md#experts){.internal-link target=_blank}. 🎉
|
||||
* <a href="https://github.com/tiangolo/fastapi/discussions/categories/questions?discussions_q=category%3AQuestions+is%3Aunanswered" class="external-link" target="_blank">GitHub Discussions</a>
|
||||
* <a href="https://github.com/tiangolo/fastapi/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Aquestion+-label%3Aanswered+" class="external-link" target="_blank">GitHub Issues</a>
|
||||
|
||||
In many cases you might already know the answer for those questions. 🤓
|
||||
|
||||
If you are helping a lot of people with their questions, you will become an official [FastAPI Expert](fastapi-people.md#experts){.internal-link target=_blank}. 🎉
|
||||
|
||||
Just remember, the most important point is: try to be kind. People come with their frustrations and in many cases don't ask in the best way, but try as best as you can to be kind. 🤗
|
||||
|
||||
@@ -81,7 +86,7 @@ The idea is for the **FastAPI** community to be kind and welcoming. At the same
|
||||
|
||||
---
|
||||
|
||||
Here's how to help others with issues:
|
||||
Here's how to help others with questions (in discussions or issues):
|
||||
|
||||
### Understand the question
|
||||
|
||||
@@ -113,24 +118,27 @@ In many cases they will only copy a fragment of the code, but that's not enough
|
||||
|
||||
If they reply, there's a high chance you would have solved their problem, congrats, **you're a hero**! 🦸
|
||||
|
||||
* Now you can ask them, if that solved their problem, to **close the issue**.
|
||||
* Now, if that solved their problem, you can ask them to:
|
||||
|
||||
* In GitHub Discussions: mark the comment as the **answer**.
|
||||
* In GitHub Issues: **close** the issue**.
|
||||
|
||||
## Watch the GitHub repository
|
||||
|
||||
You can "watch" FastAPI in GitHub (clicking the "watch" button at the top right): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>. 👀
|
||||
|
||||
If you select "Watching" instead of "Releases only" you will receive notifications when someone creates a new issue.
|
||||
If you select "Watching" instead of "Releases only" you will receive notifications when someone creates a new issue or question. You can also specify that you only want to be notified about new issues, or discussions, or PRs, etc.
|
||||
|
||||
Then you can try and help them solve those issues.
|
||||
Then you can try and help them solve those questions.
|
||||
|
||||
## Create issues
|
||||
## Ask Questions
|
||||
|
||||
You can <a href="https://github.com/tiangolo/fastapi/issues/new/choose" class="external-link" target="_blank">create a new issue</a> in the GitHub repository, for example to:
|
||||
You can <a href="https://github.com/tiangolo/fastapi/discussions/new?category=questions" class="external-link" target="_blank">create a new question</a> in the GitHub repository, for example to:
|
||||
|
||||
* Ask a **question** or ask about a **problem**.
|
||||
* Suggest a new **feature**.
|
||||
|
||||
**Note**: if you create an issue, then I'm going to ask you to also help others. 😉
|
||||
**Note**: if you do it, then I'm going to ask you to also help others. 😉
|
||||
|
||||
## Review Pull Requests
|
||||
|
||||
@@ -144,7 +152,7 @@ Here's what to have in mind and how to review a pull request:
|
||||
|
||||
### Understand the problem
|
||||
|
||||
* First, make sure you **understand the problem** that the pull request is trying to solve. It might have a longer discussion in an issue.
|
||||
* First, make sure you **understand the problem** that the pull request is trying to solve. It might have a longer discussion in a GitHub Discussion or issue.
|
||||
|
||||
* There's also a good chance that the pull request is not actually needed because the problem can be solved in a **different way**. Then you can suggest or ask about that.
|
||||
|
||||
@@ -207,7 +215,7 @@ There's a lot of work to do, and for most of it, **YOU** can do it.
|
||||
|
||||
The main tasks that you can do right now are:
|
||||
|
||||
* [Help others with issues in GitHub](#help-others-with-issues-in-github){.internal-link target=_blank} (see the section above).
|
||||
* [Help others with questions in GitHub](#help-others-with-questions-in-github){.internal-link target=_blank} (see the section above).
|
||||
* [Review Pull Requests](#review-pull-requests){.internal-link target=_blank} (see the section above).
|
||||
|
||||
Those two tasks are what **consume time the most**. That's the main work of maintaining FastAPI.
|
||||
@@ -219,7 +227,7 @@ If you can help me with that, **you are helping me maintain FastAPI** and making
|
||||
Join the 👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank">Discord chat server</a> 👥 and hang out with others in the FastAPI community.
|
||||
|
||||
!!! tip
|
||||
For questions, ask them in <a href="https://github.com/tiangolo/fastapi/issues/new/choose" class="external-link" target="_blank">GitHub issues</a>, there's a much better chance you will receive help by the [FastAPI Experts](fastapi-people.md#experts){.internal-link target=_blank}.
|
||||
For questions, ask them in <a href="https://github.com/tiangolo/fastapi/discussions/new?category=questions" class="external-link" target="_blank">GitHub Discussions</a>, there's a much better chance you will receive help by the [FastAPI Experts](fastapi-people.md#experts){.internal-link target=_blank}.
|
||||
|
||||
Use the chat only for other general conversations.
|
||||
|
||||
@@ -229,9 +237,9 @@ There is also the previous <a href="https://gitter.im/tiangolo/fastapi" class="e
|
||||
|
||||
Have in mind that as chats allow more "free conversation", it's easy to ask questions that are too general and more difficult to answer, so, you might not receive answers.
|
||||
|
||||
In GitHub issues the template will guide you to write the right question so that you can more easily get a good answer, or even solve the problem yourself even before asking. And in GitHub I can make sure I always answer everything, even if it takes some time. I can't personally do that with the chat systems. 😅
|
||||
In GitHub, the template will guide you to write the right question so that you can more easily get a good answer, or even solve the problem yourself even before asking. And in GitHub I can make sure I always answer everything, even if it takes some time. I can't personally do that with the chat systems. 😅
|
||||
|
||||
Conversations in the chat systems are also not as easily searchable as in GitHub, so questions and answers might get lost in the conversation. And only the ones in GitHub issues count to become a [FastAPI Expert](fastapi-people.md#experts){.internal-link target=_blank}, so you will most probably receive more attention in GitHub issues.
|
||||
Conversations in the chat systems are also not as easily searchable as in GitHub, so questions and answers might get lost in the conversation. And only the ones in GitHub count to become a [FastAPI Expert](fastapi-people.md#experts){.internal-link target=_blank}, so you will most probably receive more attention in GitHub.
|
||||
|
||||
On the other side, there are thousands of users in the chat systems, so there's a high chance you'll find someone to talk to there, almost all the time. 😄
|
||||
|
||||
|
||||
BIN
docs/en/docs/img/sponsors/powens.png
Normal file
BIN
docs/en/docs/img/sponsors/powens.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -2,6 +2,54 @@
|
||||
|
||||
## Latest Changes
|
||||
|
||||
|
||||
## 0.90.0
|
||||
|
||||
### Upgrades
|
||||
|
||||
* ⬆️ Bump Starlette from 0.22.0 to 0.23.0. Initial PR [#5739](https://github.com/tiangolo/fastapi/pull/5739) by [@Kludex](https://github.com/Kludex).
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Add article "Tortoise ORM / FastAPI 整合快速筆記" to External Links. PR [#5496](https://github.com/tiangolo/fastapi/pull/5496) by [@Leon0824](https://github.com/Leon0824).
|
||||
* 👥 Update FastAPI People. PR [#5954](https://github.com/tiangolo/fastapi/pull/5954) by [@github-actions[bot]](https://github.com/apps/github-actions).
|
||||
* 📝 Micro-tweak help docs. PR [#5960](https://github.com/tiangolo/fastapi/pull/5960) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update new issue chooser to direct to GitHub Discussions. PR [#5948](https://github.com/tiangolo/fastapi/pull/5948) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 📝 Recommend GitHub Discussions for questions. PR [#5944](https://github.com/tiangolo/fastapi/pull/5944) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Add Russian translation for `docs/ru/docs/tutorial/body-fields.md`. PR [#5898](https://github.com/tiangolo/fastapi/pull/5898) by [@simatheone](https://github.com/simatheone).
|
||||
* 🌐 Add Russian translation for `docs/ru/docs/help-fastapi.md`. PR [#5970](https://github.com/tiangolo/fastapi/pull/5970) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/static-files.md`. PR [#5858](https://github.com/tiangolo/fastapi/pull/5858) by [@batlopes](https://github.com/batlopes).
|
||||
* 🌐 Add Portuguese translation for `docs/pt/docs/tutorial/encoder.md`. PR [#5525](https://github.com/tiangolo/fastapi/pull/5525) by [@felipebpl](https://github.com/felipebpl).
|
||||
* 🌐 Add Russian translation for `docs/ru/docs/contributing.md`. PR [#5870](https://github.com/tiangolo/fastapi/pull/5870) by [@Xewus](https://github.com/Xewus).
|
||||
|
||||
### Internal
|
||||
|
||||
* ⬆️ Upgrade Ubuntu version for docs workflow. PR [#5971](https://github.com/tiangolo/fastapi/pull/5971) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update sponsors badges. PR [#5943](https://github.com/tiangolo/fastapi/pull/5943) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ✨ Compute FastAPI Experts including GitHub Discussions. PR [#5941](https://github.com/tiangolo/fastapi/pull/5941) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆️ Upgrade isort and update pre-commit. PR [#5940](https://github.com/tiangolo/fastapi/pull/5940) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Add template for questions in Discussions. PR [#5920](https://github.com/tiangolo/fastapi/pull/5920) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update Sponsor Budget Insight to Powens. PR [#5916](https://github.com/tiangolo/fastapi/pull/5916) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 🔧 Update GitHub Sponsors badge data. PR [#5915](https://github.com/tiangolo/fastapi/pull/5915) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
## 0.89.1
|
||||
|
||||
### Fixes
|
||||
|
||||
* 🐛 Ignore Response classes on return annotation. PR [#5855](https://github.com/tiangolo/fastapi/pull/5855) by [@Kludex](https://github.com/Kludex). See the new docs in the PR below.
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Update docs and examples for Response Model with Return Type Annotations, and update runtime error. PR [#5873](https://github.com/tiangolo/fastapi/pull/5873) by [@tiangolo](https://github.com/tiangolo). New docs at [Response Model - Return Type: Other Return Type Annotations](https://fastapi.tiangolo.com/tutorial/response-model/#other-return-type-annotations).
|
||||
* 📝 Add External Link: FastAPI lambda container: serverless simplified. PR [#5784](https://github.com/tiangolo/fastapi/pull/5784) by [@rafrasenberg](https://github.com/rafrasenberg).
|
||||
|
||||
### Translations
|
||||
|
||||
* 🌐 Add Turkish translation for `docs/tr/docs/tutorial/first_steps.md`. PR [#5691](https://github.com/tiangolo/fastapi/pull/5691) by [@Kadermiyanyedi](https://github.com/Kadermiyanyedi).
|
||||
|
||||
## 0.89.0
|
||||
|
||||
### Features
|
||||
|
||||
@@ -89,6 +89,8 @@ If you declare both a return type and a `response_model`, the `response_model` w
|
||||
|
||||
This way you can add correct type annotations to your functions even when you are returning a type different than the response model, to be used by the editor and tools like mypy. And still you can have FastAPI do the data validation, documentation, etc. using the `response_model`.
|
||||
|
||||
You can also use `response_model=None` to disable creating a response model for that *path operation*, you might need to do it if you are adding type annotations for things that are not valid Pydantic fields, you will see an example of that in one of the sections below.
|
||||
|
||||
## Return the same input data
|
||||
|
||||
Here we are declaring a `UserIn` model, it will contain a plaintext password:
|
||||
@@ -244,6 +246,74 @@ And both models will be used for the interactive API documentation:
|
||||
|
||||
<img src="/img/tutorial/response-model/image02.png">
|
||||
|
||||
## Other Return Type Annotations
|
||||
|
||||
There might be cases where you return something that is not a valid Pydantic field and you annotate it in the function, only to get the support provided by tooling (the editor, mypy, etc).
|
||||
|
||||
### Return a Response Directly
|
||||
|
||||
The most common case would be [returning a Response directly as explained later in the advanced docs](../advanced/response-directly.md){.internal-link target=_blank}.
|
||||
|
||||
```Python hl_lines="8 10-11"
|
||||
{!> ../../../docs_src/response_model/tutorial003_02.py!}
|
||||
```
|
||||
|
||||
This simple case is handled automatically by FastAPI because the return type annotation is the class (or a subclass) of `Response`.
|
||||
|
||||
And tools will also be happy because both `RedirectResponse` and `JSONResponse` are subclasses of `Response`, so the type annotation is correct.
|
||||
|
||||
### Annotate a Response Subclass
|
||||
|
||||
You can also use a subclass of `Response` in the type annotation:
|
||||
|
||||
```Python hl_lines="8-9"
|
||||
{!> ../../../docs_src/response_model/tutorial003_03.py!}
|
||||
```
|
||||
|
||||
This will also work because `RedirectResponse` is a subclass of `Response`, and FastAPI will automatically handle this simple case.
|
||||
|
||||
### Invalid Return Type Annotations
|
||||
|
||||
But when you return some other arbitrary object that is not a valid Pydantic type (e.g. a database object) and you annotate it like that in the function, FastAPI will try to create a Pydantic response model from that type annotation, and will fail.
|
||||
|
||||
The same would happen if you had something like a <abbr title='A union between multiple types means "any of these types".'>union</abbr> between different types where one or more of them are not valid Pydantic types, for example this would fail 💥:
|
||||
|
||||
=== "Python 3.6 and above"
|
||||
|
||||
```Python hl_lines="10"
|
||||
{!> ../../../docs_src/response_model/tutorial003_04.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.10 and above"
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!> ../../../docs_src/response_model/tutorial003_04_py310.py!}
|
||||
```
|
||||
|
||||
...this fails because the type annotation is not a Pydantic type and is not just a single `Response` class or subclass, it's a union (any of the two) between a `Response` and a `dict`.
|
||||
|
||||
### Disable Response Model
|
||||
|
||||
Continuing from the example above, you might not want to have the default data validation, documentation, filtering, etc. that is performed by FastAPI.
|
||||
|
||||
But you might want to still keep the return type annotation in the function to get the support from tools like editors and type checkers (e.g. mypy).
|
||||
|
||||
In this case, you can disable the response model generation by setting `response_model=None`:
|
||||
|
||||
=== "Python 3.6 and above"
|
||||
|
||||
```Python hl_lines="9"
|
||||
{!> ../../../docs_src/response_model/tutorial003_05.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.10 and above"
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!> ../../../docs_src/response_model/tutorial003_05_py310.py!}
|
||||
```
|
||||
|
||||
This will make FastAPI skip the response model generation and that way you can have any return type annotations you need without it affecting your FastAPI application. 🤓
|
||||
|
||||
## Response Model encoding parameters
|
||||
|
||||
Your response model could have default values, like:
|
||||
|
||||
42
docs/pt/docs/tutorial/encoder.md
Normal file
42
docs/pt/docs/tutorial/encoder.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Codificador Compatível com JSON
|
||||
|
||||
Existem alguns casos em que você pode precisar converter um tipo de dados (como um modelo Pydantic) para algo compatível com JSON (como um `dict`, `list`, etc).
|
||||
|
||||
Por exemplo, se você precisar armazená-lo em um banco de dados.
|
||||
|
||||
Para isso, **FastAPI** fornece uma função `jsonable_encoder()`.
|
||||
|
||||
## Usando a função `jsonable_encoder`
|
||||
|
||||
Vamos imaginar que você tenha um banco de dados `fake_db` que recebe apenas dados compatíveis com JSON.
|
||||
|
||||
Por exemplo, ele não recebe objetos `datetime`, pois estes objetos não são compatíveis com JSON.
|
||||
|
||||
Então, um objeto `datetime` teria que ser convertido em um `str` contendo os dados no formato <a href="https://en.wikipedia.org/wiki/ISO_8601" class="external-link" target="_blank">ISO</a>.
|
||||
|
||||
Da mesma forma, este banco de dados não receberia um modelo Pydantic (um objeto com atributos), apenas um `dict`.
|
||||
|
||||
Você pode usar a função `jsonable_encoder` para resolver isso.
|
||||
|
||||
A função recebe um objeto, como um modelo Pydantic e retorna uma versão compatível com JSON:
|
||||
|
||||
=== "Python 3.6 e acima"
|
||||
|
||||
```Python hl_lines="5 22"
|
||||
{!> ../../../docs_src/encoder/tutorial001.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.10 e acima"
|
||||
|
||||
```Python hl_lines="4 21"
|
||||
{!> ../../../docs_src/encoder/tutorial001_py310.py!}
|
||||
```
|
||||
|
||||
Neste exemplo, ele converteria o modelo Pydantic em um `dict`, e o `datetime` em um `str`.
|
||||
|
||||
O resultado de chamar a função é algo que pode ser codificado com o padrão do Python <a href="https://docs.python.org/3/library/json.html#json.dumps" class="external-link" target="_blank">`json.dumps()`</a>.
|
||||
|
||||
A função não retorna um grande `str` contendo os dados no formato JSON (como uma string). Mas sim, retorna uma estrutura de dados padrão do Python (por exemplo, um `dict`) com valores e subvalores compatíveis com JSON.
|
||||
|
||||
!!! nota
|
||||
`jsonable_encoder` é realmente usado pelo **FastAPI** internamente para converter dados. Mas também é útil em muitos outros cenários.
|
||||
39
docs/pt/docs/tutorial/static-files.md
Normal file
39
docs/pt/docs/tutorial/static-files.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Arquivos Estáticos
|
||||
|
||||
Você pode servir arquivos estáticos automaticamente de um diretório usando `StaticFiles`.
|
||||
|
||||
## Use `StaticFiles`
|
||||
|
||||
* Importe `StaticFiles`.
|
||||
* "Monte" uma instância de `StaticFiles()` em um caminho específico.
|
||||
|
||||
```Python hl_lines="2 6"
|
||||
{!../../../docs_src/static_files/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! note "Detalhes técnicos"
|
||||
Você também pode usar `from starlette.staticfiles import StaticFiles`.
|
||||
|
||||
O **FastAPI** fornece o mesmo que `starlette.staticfiles` como `fastapi.staticfiles` apenas como uma conveniência para você, o desenvolvedor. Mas na verdade vem diretamente da Starlette.
|
||||
|
||||
### O que é "Montagem"
|
||||
|
||||
"Montagem" significa adicionar um aplicativo completamente "independente" em uma rota específica, que então cuida de todas as subrotas.
|
||||
|
||||
Isso é diferente de usar um `APIRouter`, pois um aplicativo montado é completamente independente. A OpenAPI e a documentação do seu aplicativo principal não incluirão nada do aplicativo montado, etc.
|
||||
|
||||
Você pode ler mais sobre isso no **Guia Avançado do Usuário**.
|
||||
|
||||
## Detalhes
|
||||
|
||||
O primeiro `"/static"` refere-se à subrota em que este "subaplicativo" será "montado". Portanto, qualquer caminho que comece com `"/static"` será tratado por ele.
|
||||
|
||||
O `directory="static"` refere-se ao nome do diretório que contém seus arquivos estáticos.
|
||||
|
||||
O `name="static"` dá a ela um nome que pode ser usado internamente pelo FastAPI.
|
||||
|
||||
Todos esses parâmetros podem ser diferentes de "`static`", ajuste-os de acordo com as necessidades e detalhes específicos de sua própria aplicação.
|
||||
|
||||
## Mais informações
|
||||
|
||||
Para mais detalhes e opções, verifique <a href="https://www.starlette.io/staticfiles/" class="external-link" target="_blank">Starlette's docs about Static Files</a>.
|
||||
@@ -77,9 +77,11 @@ nav:
|
||||
- tutorial/request-forms.md
|
||||
- tutorial/request-forms-and-files.md
|
||||
- tutorial/handling-errors.md
|
||||
- tutorial/encoder.md
|
||||
- Segurança:
|
||||
- tutorial/security/index.md
|
||||
- tutorial/background-tasks.md
|
||||
- tutorial/static-files.md
|
||||
- Guia de Usuário Avançado:
|
||||
- advanced/index.md
|
||||
- Implantação:
|
||||
|
||||
469
docs/ru/docs/contributing.md
Normal file
469
docs/ru/docs/contributing.md
Normal file
@@ -0,0 +1,469 @@
|
||||
# Участие в разработке фреймворка
|
||||
|
||||
Возможно, для начала Вам стоит ознакомиться с основными способами [помочь FastAPI или получить помощь](help-fastapi.md){.internal-link target=_blank}.
|
||||
|
||||
## Разработка
|
||||
|
||||
Если Вы уже склонировали репозиторий и знаете, что Вам нужно более глубокое погружение в код фреймворка, то здесь представлены некоторые инструкции по настройке виртуального окружения.
|
||||
|
||||
### Виртуальное окружение с помощью `venv`
|
||||
|
||||
Находясь в нужной директории, Вы можете создать виртуальное окружение при помощи Python модуля `venv`.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ python -m venv env
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Эта команда создаст директорию `./env/` с бинарными (двоичными) файлами Python, а затем Вы сможете скачивать и устанавливать необходимые библиотеки в изолированное виртуальное окружение.
|
||||
|
||||
### Активация виртуального окружения
|
||||
|
||||
Активируйте виртуально окружение командой:
|
||||
|
||||
=== "Linux, macOS"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ source ./env/bin/activate
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
=== "Windows PowerShell"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ .\env\Scripts\Activate.ps1
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
=== "Windows Bash"
|
||||
|
||||
Если Вы пользуетесь Bash для Windows (например: <a href="https://gitforwindows.org/" class="external-link" target="_blank">Git Bash</a>):
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ source ./env/Scripts/activate
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Проверьте, что всё сработало:
|
||||
|
||||
=== "Linux, macOS, Windows Bash"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ which pip
|
||||
|
||||
some/directory/fastapi/env/bin/pip
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
=== "Windows PowerShell"
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ Get-Command pip
|
||||
|
||||
some/directory/fastapi/env/bin/pip
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Ели в терминале появится ответ, что бинарник `pip` расположен по пути `.../env/bin/pip`, значит всё в порядке. 🎉
|
||||
|
||||
Во избежание ошибок в дальнейших шагах, удостоверьтесь, что в Вашем виртуальном окружении установлена последняя версия `pip`:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ python -m pip install --upgrade pip
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
!!! tip "Подсказка"
|
||||
Каждый раз, перед установкой новой библиотеки в виртуальное окружение при помощи `pip`, не забудьте активировать это виртуальное окружение.
|
||||
|
||||
Это гарантирует, что если Вы используете библиотеку, установленную этим пакетом, то Вы используете библиотеку из Вашего локального окружения, а не любую другую, которая может быть установлена глобально.
|
||||
|
||||
### pip
|
||||
|
||||
После активации виртуального окружения, как было указано ранее, введите следующую команду:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ pip install -e ."[dev,doc,test]"
|
||||
|
||||
---> 100%
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Это установит все необходимые зависимости в локальное окружение для Вашего локального FastAPI.
|
||||
|
||||
#### Использование локального FastAPI
|
||||
|
||||
Если Вы создаёте Python файл, который импортирует и использует FastAPI,а затем запускаете его интерпретатором Python из Вашего локального окружения, то он будет использовать код из локального FastAPI.
|
||||
|
||||
И, так как при вводе вышеупомянутой команды был указан флаг `-e`, если Вы измените код локального FastAPI, то при следующем запуске этого файла, он будет использовать свежую версию локального FastAPI, который Вы только что изменили.
|
||||
|
||||
Таким образом, Вам не нужно "переустанавливать" Вашу локальную версию, чтобы протестировать каждое изменение.
|
||||
|
||||
### Форматировние
|
||||
|
||||
Скачанный репозиторий содержит скрипт, который может отформатировать и подчистить Ваш код:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ bash scripts/format.sh
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Заодно он упорядочит Ваши импорты.
|
||||
|
||||
Чтобы он сортировал их правильно, необходимо, чтобы FastAPI был установлен локально в Вашей среде, с помощью команды из раздела выше, использующей флаг `-e`.
|
||||
|
||||
## Документация
|
||||
|
||||
Прежде всего, убедитесь, что Вы настроили своё окружение, как описано выше, для установки всех зависимостей.
|
||||
|
||||
Документация использует <a href="https://www.mkdocs.org/" class="external-link" target="_blank">MkDocs</a>.
|
||||
|
||||
Также существуют дополнительные инструменты/скрипты для работы с переводами в `./scripts/docs.py`.
|
||||
|
||||
!!! tip "Подсказка"
|
||||
|
||||
Нет необходимости заглядывать в `./scripts/docs.py`, просто используйте это в командной строке.
|
||||
|
||||
Вся документация имеет формат Markdown и расположена в директории `./docs/en/`.
|
||||
|
||||
Многие руководства содержат блоки кода.
|
||||
|
||||
В большинстве случаев эти блоки кода представляют собой вполне законченные приложения, которые можно запускать как есть.
|
||||
|
||||
На самом деле, эти блоки кода не написаны внутри Markdown, это Python файлы в директории `./docs_src/`.
|
||||
|
||||
И эти Python файлы включаются/вводятся в документацию при создании сайта.
|
||||
|
||||
### Тестирование документации
|
||||
|
||||
|
||||
Фактически, большинство тестов запускаются с примерами исходных файлов в документации.
|
||||
|
||||
Это помогает убедиться, что:
|
||||
|
||||
* Документация находится в актуальном состоянии.
|
||||
* Примеры из документации могут быть запущены как есть.
|
||||
* Большинство функций описаны в документации и покрыты тестами.
|
||||
|
||||
Существует скрипт, который во время локальной разработки создаёт сайт и проверяет наличие любых изменений, перезагружая его в реальном времени:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ python ./scripts/docs.py live
|
||||
|
||||
<span style="color: green;">[INFO]</span> Serving on http://127.0.0.1:8008
|
||||
<span style="color: green;">[INFO]</span> Start watching changes
|
||||
<span style="color: green;">[INFO]</span> Start detecting changes
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Он запустит сайт документации по адресу: `http://127.0.0.1:8008`.
|
||||
|
||||
|
||||
Таким образом, Вы сможете редактировать файлы с документацией или кодом и наблюдать изменения вживую.
|
||||
|
||||
#### Typer CLI (опционально)
|
||||
|
||||
|
||||
Приведенная ранее инструкция показала Вам, как запускать скрипт `./scripts/docs.py` непосредственно через интерпретатор `python` .
|
||||
|
||||
Но также можно использовать <a href="https://typer.tiangolo.com/typer-cli/" class="external-link" target="_blank">Typer CLI</a>, что позволит Вам воспользоваться автозаполнением команд в Вашем терминале.
|
||||
|
||||
Если Вы установили Typer CLI, то для включения функции автозаполнения, введите эту команду:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ typer --install-completion
|
||||
|
||||
zsh completion installed in /home/user/.bashrc.
|
||||
Completion will take effect once you restart the terminal.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Приложения и документация одновременно
|
||||
|
||||
Если Вы запускаете приложение, например так:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn tutorial001:app --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
По умолчанию Uvicorn будет использовать порт `8000` и не будет конфликтовать с сайтом документации, использующим порт `8008`.
|
||||
|
||||
### Переводы на другие языки
|
||||
|
||||
Помощь с переводами ценится КРАЙНЕ ВЫСОКО! И переводы не могут быть сделаны без помощи сообщества. 🌎 🚀
|
||||
|
||||
Ниже приведены шаги, как помочь с переводами.
|
||||
|
||||
#### Подсказки и инструкции
|
||||
|
||||
* Проверьте <a href="https://github.com/tiangolo/fastapi/pulls" class="external-link" target="_blank">существующие пул-реквесты</a> для Вашего языка. Добавьте отзывы с просьбой внести изменения, если они необходимы, или одобрите их.
|
||||
|
||||
!!! tip "Подсказка"
|
||||
Вы можете <a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/commenting-on-a-pull-request" class="external-link" target="_blank">добавлять комментарии с предложениями по изменению</a> в существующие пул-реквесты.
|
||||
|
||||
Ознакомьтесь с документацией о <a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-request-reviews" class="external-link" target="_blank">добавлении отзыва к пул-реквесту</a>, чтобы утвердить его или запросить изменения.
|
||||
|
||||
* Проверьте <a href="https://github.com/tiangolo/fastapi/issues" class="external-link" target="_blank">проблемы и вопросы</a>, чтобы узнать, есть ли кто-то, координирующий переводы для Вашего языка.
|
||||
|
||||
* Добавляйте один пул-реквест для каждой отдельной переведённой страницы. Это значительно облегчит другим его просмотр.
|
||||
|
||||
Для языков, которые я не знаю, прежде чем добавить перевод в основную ветку, я подожду пока несколько других участников сообщества проверят его.
|
||||
|
||||
* Вы также можете проверить, есть ли переводы для Вашего языка и добавить к ним отзыв, который поможет мне убедиться в правильности перевода. Тогда я смогу объединить его с основной веткой.
|
||||
|
||||
* Используйте те же самые примеры кода Python. Переводите только текст документации. Вам не нужно ничего менять, чтобы эти примеры работали.
|
||||
|
||||
* Используйте те же самые изображения, имена файлов и ссылки. Вы не должны менять ничего для сохранения работоспособности.
|
||||
|
||||
* Чтобы узнать 2-буквенный код языка, на который Вы хотите сделать перевод, Вы можете воспользоваться таблицей <a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes" class="external-link" target="_blank">Список кодов языков ISO 639-1</a>.
|
||||
|
||||
#### Существующий язык
|
||||
|
||||
Допустим, Вы хотите перевести страницу на язык, на котором уже есть какие-то переводы, например, на испанский.
|
||||
|
||||
Кодом испанского языка является `es`. А значит директория для переводов на испанский язык: `docs/es/`.
|
||||
|
||||
!!! tip "Подсказка"
|
||||
Главный ("официальный") язык - английский, директория для него `docs/en/`.
|
||||
|
||||
Вы можете запустить сервер документации на испанском:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Используйте команду "live" и передайте код языка в качестве аргумента командной строки
|
||||
$ python ./scripts/docs.py live es
|
||||
|
||||
<span style="color: green;">[INFO]</span> Serving on http://127.0.0.1:8008
|
||||
<span style="color: green;">[INFO]</span> Start watching changes
|
||||
<span style="color: green;">[INFO]</span> Start detecting changes
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Теперь Вы можете перейти по адресу: <a href="http://127.0.0.1:8008" class="external-link" target="_blank">http://127.0.0.1:8008</a> и наблюдать вносимые Вами изменения вживую.
|
||||
|
||||
|
||||
Если Вы посмотрите на сайт документации FastAPI, то увидите, что все страницы есть на каждом языке. Но некоторые страницы не переведены и имеют уведомление об отсутствующем переводе.
|
||||
|
||||
Но когда Вы запускаете сайт локально, Вы видите только те страницы, которые уже переведены.
|
||||
|
||||
|
||||
Предположим, что Вы хотите добавить перевод страницы [Основные свойства](features.md){.internal-link target=_blank}.
|
||||
|
||||
* Скопируйте файл:
|
||||
|
||||
```
|
||||
docs/en/docs/features.md
|
||||
```
|
||||
|
||||
* Вставьте его точно в то же место, но в директорию языка, на который Вы хотите сделать перевод, например:
|
||||
|
||||
```
|
||||
docs/es/docs/features.md
|
||||
```
|
||||
|
||||
!!! tip "Подсказка"
|
||||
Заметьте, что в пути файла мы изменили только код языка с `en` на `es`.
|
||||
|
||||
* Теперь откройте файл конфигурации MkDocs для английского языка, расположенный тут:
|
||||
|
||||
```
|
||||
docs/en/mkdocs.yml
|
||||
```
|
||||
|
||||
* Найдите в файле конфигурации место, где расположена строка `docs/features.md`. Похожее на это:
|
||||
|
||||
```YAML hl_lines="8"
|
||||
site_name: FastAPI
|
||||
# More stuff
|
||||
nav:
|
||||
- FastAPI: index.md
|
||||
- Languages:
|
||||
- en: /
|
||||
- es: /es/
|
||||
- features.md
|
||||
```
|
||||
|
||||
* Откройте файл конфигурации MkDocs для языка, на который Вы переводите, например:
|
||||
|
||||
```
|
||||
docs/es/mkdocs.yml
|
||||
```
|
||||
|
||||
* Добавьте строку `docs/features.md` точно в то же место, как и в случае для английского, как-то так:
|
||||
|
||||
```YAML hl_lines="8"
|
||||
site_name: FastAPI
|
||||
# More stuff
|
||||
nav:
|
||||
- FastAPI: index.md
|
||||
- Languages:
|
||||
- en: /
|
||||
- es: /es/
|
||||
- features.md
|
||||
```
|
||||
|
||||
Убедитесь, что при наличии других записей, новая запись с Вашим переводом находится точно в том же порядке, что и в английской версии.
|
||||
|
||||
Если Вы зайдёте в свой браузер, то увидите, что в документации стал отображаться Ваш новый раздел.🎉
|
||||
|
||||
Теперь Вы можете переводить эту страницу и смотреть, как она выглядит при сохранении файла.
|
||||
|
||||
#### Новый язык
|
||||
|
||||
Допустим, Вы хотите добавить перевод для языка, на который пока что не переведена ни одна страница.
|
||||
|
||||
Скажем, Вы решили сделать перевод для креольского языка, но его еще нет в документации.
|
||||
|
||||
Перейдите в таблицу кодов языков по ссылке указанной выше, где найдёте, что кодом креольского языка является `ht`.
|
||||
|
||||
Затем запустите скрипт, генерирующий директорию для переводов на новые языки:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Используйте команду new-lang и передайте код языка в качестве аргумента командной строки
|
||||
$ python ./scripts/docs.py new-lang ht
|
||||
|
||||
Successfully initialized: docs/ht
|
||||
Updating ht
|
||||
Updating en
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
После чего Вы можете проверить в своем редакторе кода, что появился новый каталог `docs/ht/`.
|
||||
|
||||
!!! tip "Подсказка"
|
||||
Создайте первый пул-реквест, который будет содержать только пустую директорию для нового языка, прежде чем добавлять переводы.
|
||||
|
||||
Таким образом, другие участники могут переводить другие страницы, пока Вы работаете над одной. 🚀
|
||||
|
||||
Начните перевод с главной страницы `docs/ht/index.md`.
|
||||
|
||||
В дальнейшем можно действовать, как указано в предыдущих инструкциях для "существующего языка".
|
||||
|
||||
##### Новый язык не поддерживается
|
||||
|
||||
Если при запуске скрипта `./scripts/docs.py live` Вы получаете сообщение об ошибке, что язык не поддерживается, что-то вроде:
|
||||
|
||||
```
|
||||
raise TemplateNotFound(template)
|
||||
jinja2.exceptions.TemplateNotFound: partials/language/xx.html
|
||||
```
|
||||
|
||||
Сие означает, что тема не поддерживает этот язык (в данном случае с поддельным 2-буквенным кодом `xx`).
|
||||
|
||||
Но не стоит переживать. Вы можете установить языком темы английский, а затем перевести текст документации.
|
||||
|
||||
Если возникла такая необходимость, отредактируйте `mkdocs.yml` для Вашего нового языка. Это будет выглядеть как-то так:
|
||||
|
||||
```YAML hl_lines="5"
|
||||
site_name: FastAPI
|
||||
# More stuff
|
||||
theme:
|
||||
# More stuff
|
||||
language: xx
|
||||
```
|
||||
|
||||
Измените `xx` (код Вашего языка) на `en` и перезапустите сервер.
|
||||
|
||||
#### Предпросмотр результата
|
||||
|
||||
Когда Вы запускаете скрипт `./scripts/docs.py` с командой `live`, то будут показаны файлы и переводы для указанного языка.
|
||||
|
||||
Но когда Вы закончите, то можете посмотреть, как это будет выглядеть по-настоящему.
|
||||
|
||||
Для этого сначала создайте всю документацию:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Используйте команду "build-all", это займёт немного времени
|
||||
$ python ./scripts/docs.py build-all
|
||||
|
||||
Updating es
|
||||
Updating en
|
||||
Building docs for: en
|
||||
Building docs for: es
|
||||
Successfully built docs for: es
|
||||
Copying en index.md to README.md
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Скрипт сгенерирует `./docs_build/` для каждого языка. Он добавит все файлы с отсутствующими переводами с пометкой о том, что "у этого файла еще нет перевода". Но Вам не нужно ничего делать с этим каталогом.
|
||||
|
||||
Затем он создаст независимые сайты MkDocs для каждого языка, объединит их и сгенерирует конечный результат на `./site/`.
|
||||
|
||||
После чего Вы сможете запустить сервер со всеми языками командой `serve`:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
// Используйте команду "serve" после того, как отработает команда "build-all"
|
||||
$ python ./scripts/docs.py serve
|
||||
|
||||
Warning: this is a very simple server. For development, use mkdocs serve instead.
|
||||
This is here only to preview a site with translations already built.
|
||||
Make sure you run the build-all command first.
|
||||
Serving at: http://127.0.0.1:8008
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Тесты
|
||||
|
||||
Также в репозитории есть скрипт, который Вы можете запустить локально, чтобы протестировать весь код и сгенерировать отчеты о покрытии тестами в HTML:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ bash scripts/test-cov-html.sh
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Эта команда создаст директорию `./htmlcov/`, в которой будет файл `./htmlcov/index.html`. Открыв его в Вашем браузере, Вы можете в интерактивном режиме изучить, все ли части кода охвачены тестами.
|
||||
257
docs/ru/docs/help-fastapi.md
Normal file
257
docs/ru/docs/help-fastapi.md
Normal file
@@ -0,0 +1,257 @@
|
||||
# Помочь FastAPI - Получить помощь
|
||||
|
||||
Нравится ли Вам **FastAPI**?
|
||||
|
||||
Хотели бы Вы помочь FastAPI, его пользователям и автору?
|
||||
|
||||
Может быть у Вас возникли трудности с **FastAPI** и Вам нужна помощь?
|
||||
|
||||
Есть несколько очень простых способов оказания помощи (иногда достаточно всего лишь одного или двух кликов).
|
||||
|
||||
И также есть несколько способов получить помощь.
|
||||
|
||||
## Подписаться на новостную рассылку
|
||||
|
||||
Вы можете подписаться на редкую [новостную рассылку **FastAPI и его друзья**](/newsletter/){.internal-link target=_blank} и быть в курсе о:
|
||||
|
||||
* Новостях о FastAPI и его друзьях 🚀
|
||||
* Руководствах 📝
|
||||
* Возможностях ✨
|
||||
* Исправлениях 🚨
|
||||
* Подсказках и хитростях ✅
|
||||
|
||||
## Подписаться на FastAPI в Twitter
|
||||
|
||||
<a href="https://twitter.com/fastapi" class="external-link" target="_blank">Подписаться на @fastapi в **Twitter**</a> для получения наисвежайших новостей о **FastAPI**. 🐦
|
||||
|
||||
## Добавить **FastAPI** звезду на GitHub
|
||||
|
||||
Вы можете добавить FastAPI "звезду" на GitHub (кликнуть на кнопку звезды в верхнем правом углу экрана): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>. ⭐️
|
||||
|
||||
Чем больше звёзд, тем легче другим пользователям найти нас и увидеть, что проект уже стал полезным для многих.
|
||||
|
||||
## Отслеживать свежие выпуски в репозитории на GitHub
|
||||
|
||||
Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>. 👀
|
||||
|
||||
Там же Вы можете указать в настройках - "Releases only".
|
||||
|
||||
С такой настройкой Вы будете получать уведомления на вашу электронную почту каждый раз, когда появится новый релиз (новая версия) **FastAPI** с исправлениями ошибок и новыми возможностями.
|
||||
|
||||
## Связаться с автором
|
||||
|
||||
Можно связаться со <a href="https://tiangolo.com" class="external-link" target="_blank">мной (Себястьян Рамирез / `tiangolo`)</a>, автором FastAPI.
|
||||
|
||||
Вы можете:
|
||||
|
||||
* <a href="https://github.com/tiangolo" class="external-link" target="_blank">Подписаться на меня на **GitHub**</a>.
|
||||
* Посмотреть другие мои проекты с открытым кодом, которые могут быть полезны Вам.
|
||||
* Подписавшись на меня Вы сможете получать уведомления, что я создал новый проект с открытым кодом,.
|
||||
* <a href="https://twitter.com/tiangolo" class="external-link" target="_blank">Подписаться на меня в **Twitter**</a> или в <a href="https://fosstodon.org/@tiangolo" class="external-link" target="_blank">Mastodon</a>.
|
||||
* Поделиться со мной, как Вы используете FastAPI (я обожаю читать про это).
|
||||
* Получать уведомления, когда я делаю объявления и представляю новые инструменты.
|
||||
* Вы также можете <a href="https://twitter.com/fastapi" class="external-link" target="_blank">подписаться на @fastapi в Twitter</a> (это отдельный аккаунт).
|
||||
* <a href="https://www.linkedin.com/in/tiangolo/" class="external-link" target="_blank">Подписаться на меня в **Linkedin**</a>.
|
||||
* Получать уведомления, когда я делаю объявления и представляю новые инструменты (правда чаще всего я использую Twitter 🤷♂).
|
||||
* Читать, что я пишу (или подписаться на меня) в <a href="https://dev.to/tiangolo" class="external-link" target="_blank">**Dev.to**</a> или в <a href="https://medium.com/@tiangolo" class="external-link" target="_blank">**Medium**</a>.
|
||||
* Читать другие идеи, статьи и читать об инструментах созданных мной.
|
||||
* Подпишитесь на меня, чтобы прочитать, когда я опубликую что-нибудь новое.
|
||||
|
||||
## Оставить сообщение в Twitter о **FastAPI**
|
||||
|
||||
<a href="https://twitter.com/compose/tweet?text=I'm loving @fastapi because... https://github.com/tiangolo/fastapi" class="external-link" target="_blank">Оставьте сообщение в Twitter о **FastAPI**</a> и позвольте мне и другим узнать - почему он Вам нравится. 🎉
|
||||
|
||||
Я люблю узнавать о том, как **FastAPI** используется, что Вам понравилось в нём, в каких проектах/компаниях Вы используете его и т.п.
|
||||
|
||||
## Оставить голос за FastAPI
|
||||
|
||||
* <a href="https://www.slant.co/options/34241/~fastapi-review" class="external-link" target="_blank">Голосуйте за **FastAPI** в Slant</a>.
|
||||
* <a href="https://alternativeto.net/software/fastapi/" class="external-link" target="_blank">Голосуйте за **FastAPI** в AlternativeTo</a>.
|
||||
* <a href="https://stackshare.io/pypi-fastapi" class="external-link" target="_blank">Расскажите, как Вы используете **FastAPI** на StackShare</a>.
|
||||
|
||||
## Помочь другим с их проблемами на GitHub
|
||||
|
||||
Вы можете посмотреть, какие <a href="https://github.com/tiangolo/fastapi/issues" class="external-link" target="_blank">проблемы</a> испытывают другие люди и попытаться помочь им. Чаще всего это вопросы, на которые, весьма вероятно, Вы уже знаете ответ. 🤓
|
||||
|
||||
Если Вы будете много помогать людям с решением их проблем, Вы можете стать официальным [Экспертом FastAPI](fastapi-people.md#experts){.internal-link target=_blank}. 🎉
|
||||
|
||||
Только помните, самое важное при этом - доброта. Столкнувшись с проблемой, люди расстраиваются и часто задают вопросы не лучшим образом, но постарайтесь быть максимально доброжелательным. 🤗
|
||||
|
||||
Идея сообщества **FastAPI** в том, чтобы быть добродушным и гостеприимными. Не допускайте издевательств или неуважительного поведения по отношению к другим. Мы должны заботиться друг о друге.
|
||||
|
||||
---
|
||||
|
||||
Как помочь другим с их проблемами:
|
||||
|
||||
### Понять вопрос
|
||||
|
||||
* Удостоверьтесь, что поняли **цель** и обстоятельства случая вопрошающего.
|
||||
|
||||
* Затем проверьте, что вопрос (в подавляющем большинстве - это вопросы) Вам **ясен**.
|
||||
|
||||
* Во многих случаях вопрос касается решения, которое пользователь придумал сам, но может быть и решение **получше**. Если Вы поймёте проблему и обстоятельства случая, то сможете предложить **альтернативное решение**.
|
||||
|
||||
* Ежели вопрос Вам непонятен, запросите больше **деталей**.
|
||||
|
||||
### Воспроизвести проблему
|
||||
|
||||
В большинстве случаев есть что-то связанное с **исходным кодом** вопрошающего.
|
||||
|
||||
И во многих случаях будет предоставлен только фрагмент этого кода, которого недостаточно для **воспроизведения проблемы**.
|
||||
|
||||
* Попросите предоставить <a href="https://stackoverflow.com/help/minimal-reproducible-example" class="external-link" target="_blank">минимальный воспроизводимый пример</a>, который можно **скопировать** и запустить локально дабы увидеть такую же ошибку, или поведение, или лучше понять обстоятельства случая.
|
||||
|
||||
* Если на Вас нахлынуло великодушие, то можете попытаться **создать похожий пример** самостоятельно, основываясь только на описании проблемы. Но имейте в виду, что это может занять много времени и, возможно, стоит сначала позадавать вопросы для прояснения проблемы.
|
||||
|
||||
### Предложить решение
|
||||
|
||||
* После того как Вы поняли вопрос, Вы можете дать **ответ**.
|
||||
|
||||
* Следует понять **основную проблему и обстоятельства случая**, потому что может быть решение лучше, чем то, которое пытались реализовать.
|
||||
|
||||
### Попросить закрыть проблему
|
||||
|
||||
Если Вам ответили, высоки шансы, что Вам удалось решить проблему, поздравляю, **Вы - герой**! 🦸
|
||||
|
||||
* В таком случае, если вопрос решён, попросите **закрыть проблему**.
|
||||
|
||||
## Отслеживать репозиторий на GitHub
|
||||
|
||||
Вы можете "отслеживать" FastAPI на GitHub (кликните по кнопке "watch" наверху справа): <a href="https://github.com/tiangolo/fastapi" class="external-link" target="_blank">https://github.com/tiangolo/fastapi</a>. 👀
|
||||
|
||||
Если Вы выберете "Watching" вместо "Releases only", то будете получать уведомления когда кто-либо попросит о помощи с решением его проблемы.
|
||||
|
||||
Тогда Вы можете попробовать решить эту проблему.
|
||||
|
||||
## Запросить помощь с решением проблемы
|
||||
|
||||
Вы можете <a href="https://github.com/tiangolo/fastapi/issues/new/choose" class="external-link" target="_blank">создать новый запрос с просьбой о помощи</a> в репозитории на GitHub, например:
|
||||
|
||||
* Задать **вопрос** или попросить помощи в решении **проблемы**.
|
||||
* Предложить новое **улучшение**.
|
||||
|
||||
**Заметка**: Если Вы создаёте подобные запросы, то я попрошу Вас также оказывать аналогичную помощь другим. 😉
|
||||
|
||||
## Проверять пул-реквесты
|
||||
|
||||
Вы можете помочь мне проверять пул-реквесты других участников.
|
||||
|
||||
И повторюсь, постарайтесь быть доброжелательным. 🤗
|
||||
|
||||
---
|
||||
|
||||
О том, что нужно иметь в виду при проверке пул-реквестов:
|
||||
|
||||
### Понять проблему
|
||||
|
||||
* Во-первых, убедитесь, что **поняли проблему**, которую пул-реквест пытается решить. Для этого может потребоваться продолжительное обсуждение.
|
||||
|
||||
* Также есть вероятность, что пул-реквест не актуален, так как проблему можно решить **другим путём**. В таком случае Вы можете указать на этот факт.
|
||||
|
||||
### Не переживайте о стиле
|
||||
|
||||
* Не стоит слишком беспокоиться о таких вещах, как стиль сообщений в коммитах или количество коммитов. При слиянии пул-реквеста с основной веткой, я буду сжимать и настраивать всё вручную.
|
||||
|
||||
* Также не беспокойтесь о правилах стиля, для проверки сего есть автоматизированные инструменты.
|
||||
|
||||
И если всё же потребуется какой-то другой стиль, я попрошу Вас об этом напрямую или добавлю сам коммиты с необходимыми изменениями.
|
||||
|
||||
### Проверить код
|
||||
|
||||
* Проверьте и прочитайте код, посмотрите, какой он имеет смысл, **запустите его локально** и посмотрите, действительно ли он решает поставленную задачу.
|
||||
|
||||
* Затем, используя **комментарий**, сообщите, что Вы сделали проверку, тогда я буду знать, что Вы действительно проверили код.
|
||||
|
||||
!!! Информация
|
||||
К сожалению, я не могу так просто доверять пул-реквестам, у которых уже есть несколько одобрений.
|
||||
|
||||
Бывали случаи, что пул-реквесты имели 3, 5 или больше одобрений, вероятно из-за привлекательного описания, но когда я проверял эти пул-реквесты, они оказывались сломаны, содержали ошибки или вовсе не решали проблему, которую, как они утверждали, должны были решить. 😅
|
||||
|
||||
Потому это действительно важно - проверять и запускать код, и комментарием уведомлять меня, что Вы проделали эти действия. 🤓
|
||||
|
||||
* Если Вы считаете, что пул-реквест можно упростить, то можете попросить об этом, но не нужно быть слишком придирчивым, может быть много субъективных точек зрения (и у меня тоже будет своя 🙈), поэтому будет лучше, если Вы сосредоточитесь на фундаментальных вещах.
|
||||
|
||||
### Тестировать
|
||||
|
||||
* Помогите мне проверить, что у пул-реквеста есть **тесты**.
|
||||
|
||||
* Проверьте, что тесты **падали** до пул-реквеста. 🚨
|
||||
|
||||
* Затем проверьте, что тесты **не валятся** после пул-реквеста. ✅
|
||||
|
||||
* Многие пул-реквесты не имеют тестов, Вы можете **напомнить** о необходимости добавления тестов или даже **предложить** какие-либо свои тесты. Это одна из тех вещей, которые отнимают много времени и Вы можете помочь с этим.
|
||||
|
||||
* Затем добавьте комментарий, что Вы испробовали в ходе проверки. Таким образом я буду знать, как Вы произвели проверку. 🤓
|
||||
|
||||
## Создать пул-реквест
|
||||
|
||||
Вы можете [сделать вклад](contributing.md){.internal-link target=_blank} в код фреймворка используя пул-реквесты, например:
|
||||
|
||||
* Исправить опечатку, которую Вы нашли в документации.
|
||||
* Поделиться статьёй, видео или подкастом о FastAPI, которые Вы создали или нашли <a href="https://github.com/tiangolo/fastapi/edit/master/docs/en/data/external_links.yml" class="external-link" target="_blank">изменив этот файл</a>.
|
||||
* Убедитесь, что Вы добавили свою ссылку в начало соответствующего раздела.
|
||||
* Помочь с [переводом документации](contributing.md#translations){.internal-link target=_blank} на Ваш язык.
|
||||
* Вы также можете проверять переводы сделанные другими.
|
||||
* Предложить новые разделы документации.
|
||||
* Исправить существующуе проблемы/баги.
|
||||
* Убедитесь, что добавили тесты.
|
||||
* Добавить новую возможность.
|
||||
* Убедитесь, что добавили тесты.
|
||||
* Убедитесь, что добавили документацию, если она необходима.
|
||||
|
||||
## Помочь поддерживать FastAPI
|
||||
|
||||
Помогите мне поддерживать **FastAPI**! 🤓
|
||||
|
||||
Предстоит ещё много работы и, по большей части, **ВЫ** можете её сделать.
|
||||
|
||||
Основные задачи, которые Вы можете выполнить прямо сейчас:
|
||||
|
||||
* [Помочь другим с их проблемами на GitHub](#help-others-with-issues-in-github){.internal-link target=_blank} (смотрите вышестоящую секцию).
|
||||
* [Проверить пул-реквесты](#review-pull-requests){.internal-link target=_blank} (смотрите вышестоящую секцию).
|
||||
|
||||
Эти две задачи **отнимают больше всего времени**. Это основная работа по поддержке FastAPI.
|
||||
|
||||
Если Вы можете помочь мне с этим, **Вы помогаете поддерживать FastAPI** и следить за тем, чтобы он продолжал **развиваться быстрее и лучше**. 🚀
|
||||
|
||||
## Подключиться к чату
|
||||
|
||||
Подключайтесь к 👥 <a href="https://discord.gg/VQjSZaeJmf" class="external-link" target="_blank"> чату в Discord</a> 👥 и общайтесь с другими участниками сообщества FastAPI.
|
||||
|
||||
!!! Подсказка
|
||||
Вопросы по проблемам с фреймворком лучше задавать в <a href="https://github.com/tiangolo/fastapi/issues/new/choose" class="external-link" target="_blank">GitHub issues</a>, так больше шансов, что Вы получите помощь от [Экспертов FastAPI](fastapi-people.md#experts){.internal-link target=_blank}.
|
||||
|
||||
Используйте этот чат только для бесед на отвлечённые темы.
|
||||
|
||||
Существует также <a href="https://gitter.im/tiangolo/fastapi" class="external-link" target="_blank">чат в Gitter</a>, но поскольку в нем нет каналов и расширенных функций, общение в нём сложнее, потому рекомендуемой системой является Discord.
|
||||
|
||||
### Не использовать чаты для вопросов
|
||||
|
||||
Имейте в виду, что чаты позволяют больше "свободного общения", потому там легко задавать вопросы, которые слишком общие и на которые труднее ответить, так что Вы можете не получить нужные Вам ответы.
|
||||
|
||||
В разделе "проблемы" на GitHub, есть шаблон, который поможет Вам написать вопрос правильно, чтобы Вам было легче получить хороший ответ или даже решить проблему самостоятельно, прежде чем Вы зададите вопрос. В GitHub я могу быть уверен, что всегда отвечаю на всё, даже если это займет какое-то время. И я не могу сделать то же самое в чатах. 😅
|
||||
|
||||
Кроме того, общение в чатах не так легкодоступно для поиска, как в GitHub, потому вопросы и ответы могут потеряться среди другого общения. И только проблемы решаемые на GitHub учитываются в получении лычки [Эксперт FastAPI](fastapi-people.md#experts){.internal-link target=_blank}, так что весьма вероятно, что Вы получите больше внимания на GitHub.
|
||||
|
||||
С другой стороны, в чатах тысячи пользователей, а значит есть большие шансы в любое время найти там кого-то, с кем можно поговорить. 😄
|
||||
|
||||
## Спонсировать автора
|
||||
|
||||
Вы также можете оказать мне финансовую поддержку посредством <a href="https://github.com/sponsors/tiangolo" class="external-link" target="_blank">спонсорства через GitHub</a>.
|
||||
|
||||
Там можно просто купить мне кофе ☕️ в знак благодарности. 😄
|
||||
|
||||
А ещё Вы можете стать Серебряным или Золотым спонсором для FastAPI. 🏅🎉
|
||||
|
||||
## Спонсировать инструменты, на которых зиждется мощь FastAPI
|
||||
|
||||
Как Вы могли заметить в документации, FastAPI опирается на плечи титанов: Starlette и Pydantic.
|
||||
|
||||
Им тоже можно оказать спонсорскую поддержку:
|
||||
|
||||
* <a href="https://github.com/sponsors/samuelcolvin" class="external-link" target="_blank">Samuel Colvin (Pydantic)</a>
|
||||
* <a href="https://github.com/sponsors/encode" class="external-link" target="_blank">Encode (Starlette, Uvicorn)</a>
|
||||
|
||||
---
|
||||
|
||||
Благодарствую! 🚀
|
||||
69
docs/ru/docs/tutorial/body-fields.md
Normal file
69
docs/ru/docs/tutorial/body-fields.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Body - Поля
|
||||
|
||||
Таким же способом, как вы объявляете дополнительную валидацию и метаданные в параметрах *функции обработки пути* с помощью функций `Query`, `Path` и `Body`, вы можете объявлять валидацию и метаданные внутри Pydantic моделей, используя функцию `Field` из Pydantic.
|
||||
|
||||
## Импорт `Field`
|
||||
|
||||
Сначала вы должны импортировать его:
|
||||
|
||||
=== "Python 3.6 и выше"
|
||||
|
||||
```Python hl_lines="4"
|
||||
{!> ../../../docs_src/body_fields/tutorial001.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.10 и выше"
|
||||
|
||||
```Python hl_lines="2"
|
||||
{!> ../../../docs_src/body_fields/tutorial001_py310.py!}
|
||||
```
|
||||
|
||||
!!! warning "Внимание"
|
||||
Обратите внимание, что функция `Field` импортируется непосредственно из `pydantic`, а не из `fastapi`, как все остальные функции (`Query`, `Path`, `Body` и т.д.).
|
||||
|
||||
## Объявление атрибутов модели
|
||||
|
||||
Вы можете использовать функцию `Field` с атрибутами модели:
|
||||
|
||||
=== "Python 3.6 и выше"
|
||||
|
||||
```Python hl_lines="11-14"
|
||||
{!> ../../../docs_src/body_fields/tutorial001.py!}
|
||||
```
|
||||
|
||||
=== "Python 3.10 и выше"
|
||||
|
||||
```Python hl_lines="9-12"
|
||||
{!> ../../../docs_src/body_fields/tutorial001_py310.py!}
|
||||
```
|
||||
|
||||
Функция `Field` работает так же, как `Query`, `Path` и `Body`, у ее такие же параметры и т.д.
|
||||
|
||||
!!! note "Технические детали"
|
||||
На самом деле, `Query`, `Path` и другие функции, которые вы увидите в дальнейшем, создают объекты подклассов общего класса `Param`, который сам по себе является подклассом `FieldInfo` из Pydantic.
|
||||
|
||||
И `Field` (из Pydantic), и `Body`, оба возвращают объекты подкласса `FieldInfo`.
|
||||
|
||||
У класса `Body` есть и другие подклассы, с которыми вы ознакомитесь позже.
|
||||
|
||||
Помните, что когда вы импортируете `Query`, `Path` и другое из `fastapi`, это фактически функции, которые возвращают специальные классы.
|
||||
|
||||
!!! tip "Подсказка"
|
||||
Обратите внимание, что каждый атрибут модели с типом, значением по умолчанию и `Field` имеет ту же структуру, что и параметр *функции обработки пути* с `Field` вместо `Path`, `Query` и `Body`.
|
||||
|
||||
## Добавление дополнительной информации
|
||||
|
||||
Вы можете объявлять дополнительную информацию в `Field`, `Query`, `Body` и т.п. Она будет включена в сгенерированную JSON схему.
|
||||
|
||||
Вы узнаете больше о добавлении дополнительной информации позже в документации, когда будете изучать, как задавать примеры принимаемых данных.
|
||||
|
||||
|
||||
!!! warning "Внимание"
|
||||
Дополнительные ключи, переданные в функцию `Field`, также будут присутствовать в сгенерированной OpenAPI схеме вашего приложения.
|
||||
Поскольку эти ключи не являются обязательной частью спецификации OpenAPI, некоторые инструменты OpenAPI, например, [валидатор OpenAPI](https://validator.swagger.io/), могут не работать с вашей сгенерированной схемой.
|
||||
|
||||
## Резюме
|
||||
|
||||
Вы можете использовать функцию `Field` из Pydantic, чтобы задавать дополнительную валидацию и метаданные для атрибутов модели.
|
||||
|
||||
Вы также можете использовать дополнительные ключевые аргументы, чтобы добавить метаданные JSON схемы.
|
||||
@@ -62,12 +62,14 @@ nav:
|
||||
- fastapi-people.md
|
||||
- python-types.md
|
||||
- Учебник - руководство пользователя:
|
||||
- tutorial/body-fields.md
|
||||
- tutorial/background-tasks.md
|
||||
- async.md
|
||||
- Развёртывание:
|
||||
- deployment/index.md
|
||||
- deployment/versions.md
|
||||
- external-links.md
|
||||
- contributing.md
|
||||
markdown_extensions:
|
||||
- toc:
|
||||
permalink: true
|
||||
|
||||
336
docs/tr/docs/tutorial/first_steps.md
Normal file
336
docs/tr/docs/tutorial/first_steps.md
Normal file
@@ -0,0 +1,336 @@
|
||||
# İlk Adımlar
|
||||
|
||||
En basit FastAPI dosyası şu şekildedir:
|
||||
|
||||
```Python
|
||||
{!../../../docs_src/first_steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
Bunu bir `main.py` dosyasına kopyalayın.
|
||||
|
||||
Projeyi çalıştırın:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
<span style="color: green;">INFO</span>: Started reloader process [28720]
|
||||
<span style="color: green;">INFO</span>: Started server process [28722]
|
||||
<span style="color: green;">INFO</span>: Waiting for application startup.
|
||||
<span style="color: green;">INFO</span>: Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
!!! note
|
||||
`uvicorn main:app` komutu şunu ifade eder:
|
||||
|
||||
* `main`: `main.py` dosyası (the Python "module").
|
||||
* `app`: `main.py` dosyası içerisinde `app = FastAPI()` satırıyla oluşturulan nesne.
|
||||
* `--reload`: Kod değişikliği sonrasında sunucunun yeniden başlatılmasını sağlar. Yalnızca geliştirme için kullanın.
|
||||
|
||||
Çıktıda şu şekilde bir satır vardır:
|
||||
|
||||
```hl_lines="4"
|
||||
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
Bu satır, yerel makinenizde uygulamanızın sunulduğu URL'yi gösterir.
|
||||
|
||||
### Kontrol Et
|
||||
|
||||
Tarayıcınızda <a href="http://127.0.0.1:8000" class="external-link" target="_blank">http://127.0.0.1:8000</a> adresini açın.
|
||||
|
||||
Bir JSON yanıtı göreceksiniz:
|
||||
|
||||
```JSON
|
||||
{"message": "Hello World"}
|
||||
```
|
||||
|
||||
### İnteraktif API dokümantasyonu
|
||||
|
||||
<a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a> adresine gidin.
|
||||
|
||||
Otomatik oluşturulmuş( <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank">Swagger UI</a> tarafından sağlanan) interaktif bir API dokümanı göreceksiniz:
|
||||
|
||||

|
||||
|
||||
### Alternatif API dokümantasyonu
|
||||
|
||||
Şimdi, <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a> adresine gidin.
|
||||
|
||||
Otomatik oluşturulmuş(<a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> tarafından sağlanan) bir API dokümanı göreceksiniz:
|
||||
|
||||

|
||||
|
||||
### OpenAPI
|
||||
|
||||
**FastAPI**, **OpenAPI** standardını kullanarak tüm API'lerinizi açıklayan bir "şema" oluşturur.
|
||||
|
||||
#### "Şema"
|
||||
|
||||
Bir "şema", bir şeyin tanımı veya açıklamasıdır. Soyut bir açıklamadır, uygulayan kod değildir.
|
||||
|
||||
#### API "şemaları"
|
||||
|
||||
Bu durumda, <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a>, API şemasını nasıl tanımlayacağınızı belirten şartnamelerdir.
|
||||
|
||||
Bu şema tanımı, API yollarınızı, aldıkları olası parametreleri vb. içerir.
|
||||
|
||||
#### Data "şema"
|
||||
|
||||
"Şema" terimi, JSON içeriği gibi bazı verilerin şeklini de ifade edebilir.
|
||||
|
||||
Bu durumda, JSON öznitelikleri ve sahip oldukları veri türleri vb. anlamına gelir.
|
||||
|
||||
#### OpenAPI and JSON Şema
|
||||
|
||||
OpenAPI, API'niz için bir API şeması tanımlar. Ve bu şema, JSON veri şemaları standardı olan **JSON Şema** kullanılarak API'niz tarafından gönderilen ve alınan verilerin tanımlarını (veya "şemalarını") içerir.
|
||||
|
||||
#### `openapi.json` kontrol et
|
||||
|
||||
OpenAPI şemasının nasıl göründüğünü merak ediyorsanız, FastAPI otomatik olarak tüm API'nizin açıklamalarını içeren bir JSON (şema) oluşturur.
|
||||
|
||||
Doğrudan şu adreste görebilirsiniz: <a href="http://127.0.0.1:8000/openapi.json" class="external-link" target="_blank">http://127.0.0.1:8000/openapi.json</a>.
|
||||
|
||||
Aşağıdaki gibi bir şeyle başlayan bir JSON gösterecektir:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"openapi": "3.0.2",
|
||||
"info": {
|
||||
"title": "FastAPI",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"paths": {
|
||||
"/items/": {
|
||||
"get": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
|
||||
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
#### OpenAPI ne içindir?
|
||||
|
||||
OpenAPI şeması, dahili olarak bulunan iki etkileşimli dokümantasyon sistemine güç veren şeydir.
|
||||
|
||||
Ve tamamen OpenAPI'ye dayalı düzinelerce alternatif vardır. **FastAPI** ile oluşturulmuş uygulamanıza bu alternatiflerden herhangi birini kolayca ekleyebilirsiniz.
|
||||
|
||||
API'nizle iletişim kuran istemciler için otomatik olarak kod oluşturmak için de kullanabilirsiniz. Örneğin, frontend, mobil veya IoT uygulamaları.
|
||||
|
||||
## Adım adım özet
|
||||
|
||||
### Adım 1: `FastAPI`yi içe aktarın
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!../../../docs_src/first_steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
`FastAPI`, API'niz için tüm fonksiyonları sağlayan bir Python sınıfıdır.
|
||||
|
||||
!!! note "Teknik Detaylar"
|
||||
`FastAPI` doğrudan `Starlette` kalıtım alan bir sınıftır.
|
||||
|
||||
Tüm <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> fonksiyonlarını `FastAPI` ile de kullanabilirsiniz.
|
||||
|
||||
### Adım 2: Bir `FastAPI` örneği oluşturun
|
||||
|
||||
```Python hl_lines="3"
|
||||
{!../../../docs_src/first_steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
Burada `app` değişkeni `FastAPI` sınıfının bir örneği olacaktır.
|
||||
|
||||
Bu tüm API'yi oluşturmak için ana etkileşim noktası olacaktır.
|
||||
|
||||
`uvicorn` komutunda atıfta bulunulan `app` ile aynıdır.
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
Uygulamanızı aşağıdaki gibi oluşturursanız:
|
||||
|
||||
```Python hl_lines="3"
|
||||
{!../../../docs_src/first_steps/tutorial002.py!}
|
||||
```
|
||||
|
||||
Ve bunu `main.py` dosyasına koyduktan sonra `uvicorn` komutunu şu şekilde çağırabilirsiniz:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```console
|
||||
$ uvicorn main:my_awesome_api --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Adım 3: *Path işlemleri* oluşturmak
|
||||
|
||||
#### Path
|
||||
|
||||
Burada "Path" URL'de ilk "\" ile başlayan son bölümü ifade eder.
|
||||
|
||||
Yani, şu şekilde bir URL'de:
|
||||
|
||||
```
|
||||
https://example.com/items/foo
|
||||
```
|
||||
|
||||
... path şöyle olabilir:
|
||||
|
||||
```
|
||||
/items/foo
|
||||
```
|
||||
|
||||
!!! info
|
||||
Genellikle bir "path", "endpoint" veya "route" olarak adlandırılabilir.
|
||||
|
||||
Bir API oluştururken, "path", "resource" ile "concern" ayırmanın ana yoludur.
|
||||
|
||||
#### İşlemler
|
||||
|
||||
Burada "işlem" HTTP methodlarından birini ifade eder.
|
||||
|
||||
Onlardan biri:
|
||||
|
||||
* `POST`
|
||||
* `GET`
|
||||
* `PUT`
|
||||
* `DELETE`
|
||||
|
||||
... ve daha egzotik olanları:
|
||||
|
||||
* `OPTIONS`
|
||||
* `HEAD`
|
||||
* `PATCH`
|
||||
* `TRACE`
|
||||
|
||||
HTTP protokolünde, bu "methodlardan" birini (veya daha fazlasını) kullanarak her path ile iletişim kurabilirsiniz.
|
||||
|
||||
---
|
||||
|
||||
API'lerinizi oluştururkan, belirli bir işlemi gerçekleştirirken belirli HTTP methodlarını kullanırsınız.
|
||||
|
||||
Normalde kullanılan:
|
||||
|
||||
* `POST`: veri oluşturmak.
|
||||
* `GET`: veri okumak.
|
||||
* `PUT`: veriyi güncellemek.
|
||||
* `DELETE`: veriyi silmek.
|
||||
|
||||
Bu nedenle, OpenAPI'de HTTP methodlarından her birine "işlem" denir.
|
||||
|
||||
Bizde onlara "**işlemler**" diyeceğiz.
|
||||
|
||||
#### Bir *Path işlem decoratorleri* tanımlanmak
|
||||
|
||||
```Python hl_lines="6"
|
||||
{!../../../docs_src/first_steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
`@app.get("/")` **FastAPI'ye** aşağıdaki fonksiyonun adresine giden istekleri işlemekten sorumlu olduğunu söyler:
|
||||
|
||||
* path `/`
|
||||
* <abbr title="an HTTP GET method"><code>get</code> işlemi</abbr> kullanılarak
|
||||
|
||||
|
||||
!!! info "`@decorator` Bilgisi"
|
||||
Python `@something` şeklinde ifadeleri "decorator" olarak adlandırır.
|
||||
|
||||
Decoratoru bir fonksiyonun üzerine koyarsınız. Dekoratif bir şapka gibi (Sanırım terim buradan gelmektedir).
|
||||
|
||||
Bir "decorator" fonksiyonu alır ve bazı işlemler gerçekleştir.
|
||||
|
||||
Bizim durumumzda decarator **FastAPI'ye** fonksiyonun bir `get` işlemi ile `/` pathine geldiğini söyler.
|
||||
|
||||
Bu **path işlem decoratordür**
|
||||
|
||||
Ayrıca diğer işlemleri de kullanabilirsiniz:
|
||||
|
||||
* `@app.post()`
|
||||
* `@app.put()`
|
||||
* `@app.delete()`
|
||||
|
||||
Ve daha egzotik olanları:
|
||||
|
||||
* `@app.options()`
|
||||
* `@app.head()`
|
||||
* `@app.patch()`
|
||||
* `@app.trace()`
|
||||
|
||||
!!! tip
|
||||
Her işlemi (HTTP method) istediğiniz gibi kullanmakta özgürsünüz.
|
||||
|
||||
**FastAPI** herhangi bir özel anlamı zorlamaz.
|
||||
|
||||
Buradaki bilgiler bir gereklilik değil, bir kılavuz olarak sunulmaktadır.
|
||||
|
||||
Örneğin, GraphQL kullanırkan normalde tüm işlemleri yalnızca `POST` işlemini kullanarak gerçekleştirirsiniz.
|
||||
|
||||
### Adım 4: **path işlem fonksiyonunu** tanımlayın
|
||||
|
||||
Aşağıdakiler bizim **path işlem fonksiyonlarımızdır**:
|
||||
|
||||
* **path**: `/`
|
||||
* **işlem**: `get`
|
||||
* **function**: "decorator"ün altındaki fonksiyondur (`@app.get("/")` altında).
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!../../../docs_src/first_steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
Bu bir Python fonksiyonudur.
|
||||
|
||||
Bir `GET` işlemi kullanarak "`/`" URL'sine bir istek geldiğinde **FastAPI** tarafından çağrılır.
|
||||
|
||||
Bu durumda bir `async` fonksiyonudur.
|
||||
|
||||
---
|
||||
|
||||
Bunu `async def` yerine normal bir fonksiyon olarakta tanımlayabilirsiniz.
|
||||
|
||||
```Python hl_lines="7"
|
||||
{!../../../docs_src/first_steps/tutorial003.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
Eğer farkı bilmiyorsanız, [Async: *"Acelesi var?"*](../async.md#in-a-hurry){.internal-link target=_blank} kontrol edebilirsiniz.
|
||||
|
||||
### Adım 5: İçeriği geri döndürün
|
||||
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!../../../docs_src/first_steps/tutorial001.py!}
|
||||
```
|
||||
|
||||
Bir `dict`, `list` döndürebilir veya `str`, `int` gibi tekil değerler döndürebilirsiniz.
|
||||
|
||||
Ayrıca, Pydantic modellerini de döndürebilirsiniz. (Bununla ilgili daha sonra ayrıntılı bilgi göreceksiniz.)
|
||||
|
||||
Otomatik olarak JSON'a dönüştürülecek(ORM'ler vb. dahil) başka birçok nesne ve model vardır. En beğendiklerinizi kullanmayı deneyin, yüksek ihtimalle destekleniyordur.
|
||||
|
||||
## Özet
|
||||
|
||||
* `FastAPI`'yi içe aktarın.
|
||||
* Bir `app` örneği oluşturun.
|
||||
* **path işlem decorator** yazın. (`@app.get("/")` gibi)
|
||||
* **path işlem fonksiyonu** yazın. (`def root(): ...` gibi)
|
||||
* Development sunucunuzu çalıştırın. (`uvicorn main:app --reload` gibi)
|
||||
@@ -61,6 +61,8 @@ nav:
|
||||
- features.md
|
||||
- fastapi-people.md
|
||||
- python-types.md
|
||||
- Tutorial - User Guide:
|
||||
- tutorial/first-steps.md
|
||||
markdown_extensions:
|
||||
- toc:
|
||||
permalink: true
|
||||
|
||||
@@ -10,7 +10,7 @@ async def read_main():
|
||||
return {"msg": "Hello World"}
|
||||
|
||||
|
||||
@app.websocket_route("/ws")
|
||||
@app.websocket("/ws")
|
||||
async def websocket(websocket: WebSocket):
|
||||
await websocket.accept()
|
||||
await websocket.send_json({"msg": "Hello WebSocket"})
|
||||
|
||||
11
docs_src/response_model/tutorial003_02.py
Normal file
11
docs_src/response_model/tutorial003_02.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from fastapi import FastAPI, Response
|
||||
from fastapi.responses import JSONResponse, RedirectResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/portal")
|
||||
async def get_portal(teleport: bool = False) -> Response:
|
||||
if teleport:
|
||||
return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
|
||||
return JSONResponse(content={"message": "Here's your interdimensional portal."})
|
||||
9
docs_src/response_model/tutorial003_03.py
Normal file
9
docs_src/response_model/tutorial003_03.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import RedirectResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/teleport")
|
||||
async def get_teleport() -> RedirectResponse:
|
||||
return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
|
||||
13
docs_src/response_model/tutorial003_04.py
Normal file
13
docs_src/response_model/tutorial003_04.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI, Response
|
||||
from fastapi.responses import RedirectResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/portal")
|
||||
async def get_portal(teleport: bool = False) -> Union[Response, dict]:
|
||||
if teleport:
|
||||
return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
|
||||
return {"message": "Here's your interdimensional portal."}
|
||||
11
docs_src/response_model/tutorial003_04_py310.py
Normal file
11
docs_src/response_model/tutorial003_04_py310.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from fastapi import FastAPI, Response
|
||||
from fastapi.responses import RedirectResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/portal")
|
||||
async def get_portal(teleport: bool = False) -> Response | dict:
|
||||
if teleport:
|
||||
return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
|
||||
return {"message": "Here's your interdimensional portal."}
|
||||
13
docs_src/response_model/tutorial003_05.py
Normal file
13
docs_src/response_model/tutorial003_05.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI, Response
|
||||
from fastapi.responses import RedirectResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/portal", response_model=None)
|
||||
async def get_portal(teleport: bool = False) -> Union[Response, dict]:
|
||||
if teleport:
|
||||
return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
|
||||
return {"message": "Here's your interdimensional portal."}
|
||||
11
docs_src/response_model/tutorial003_05_py310.py
Normal file
11
docs_src/response_model/tutorial003_05_py310.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from fastapi import FastAPI, Response
|
||||
from fastapi.responses import RedirectResponse
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/portal", response_model=None)
|
||||
async def get_portal(teleport: bool = False) -> Response | dict:
|
||||
if teleport:
|
||||
return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
|
||||
return {"message": "Here's your interdimensional portal."}
|
||||
@@ -1,6 +1,6 @@
|
||||
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
|
||||
|
||||
__version__ = "0.89.0"
|
||||
__version__ = "0.90.0"
|
||||
|
||||
from starlette import status as status
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ from starlette.applications import Starlette
|
||||
from starlette.datastructures import State
|
||||
from starlette.exceptions import HTTPException
|
||||
from starlette.middleware import Middleware
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from starlette.middleware.errors import ServerErrorMiddleware
|
||||
from starlette.middleware.exceptions import ExceptionMiddleware
|
||||
from starlette.requests import Request
|
||||
@@ -870,3 +871,35 @@ class FastAPI(Starlette):
|
||||
openapi_extra=openapi_extra,
|
||||
generate_unique_id_function=generate_unique_id_function,
|
||||
)
|
||||
|
||||
def websocket_route(
|
||||
self, path: str, name: Union[str, None] = None
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
def decorator(func: DecoratedCallable) -> DecoratedCallable:
|
||||
self.router.add_websocket_route(path, func, name=name)
|
||||
return func
|
||||
|
||||
return decorator
|
||||
|
||||
def on_event(
|
||||
self, event_type: str
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
return self.router.on_event(event_type)
|
||||
|
||||
def middleware(
|
||||
self, middleware_type: str
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
def decorator(func: DecoratedCallable) -> DecoratedCallable:
|
||||
self.add_middleware(BaseHTTPMiddleware, dispatch=func)
|
||||
return func
|
||||
|
||||
return decorator
|
||||
|
||||
def exception_handler(
|
||||
self, exc_class_or_status_code: Union[int, Type[Exception]]
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
def decorator(func: DecoratedCallable) -> DecoratedCallable:
|
||||
self.add_exception_handler(exc_class_or_status_code, func)
|
||||
return func
|
||||
|
||||
return decorator
|
||||
|
||||
@@ -42,6 +42,7 @@ from fastapi.utils import (
|
||||
from pydantic import BaseModel
|
||||
from pydantic.error_wrappers import ErrorWrapper, ValidationError
|
||||
from pydantic.fields import ModelField, Undefined
|
||||
from pydantic.utils import lenient_issubclass
|
||||
from starlette import routing
|
||||
from starlette.concurrency import run_in_threadpool
|
||||
from starlette.exceptions import HTTPException
|
||||
@@ -356,7 +357,11 @@ class APIRoute(routing.Route):
|
||||
self.path = path
|
||||
self.endpoint = endpoint
|
||||
if isinstance(response_model, DefaultPlaceholder):
|
||||
response_model = get_typed_return_annotation(endpoint)
|
||||
return_annotation = get_typed_return_annotation(endpoint)
|
||||
if lenient_issubclass(return_annotation, Response):
|
||||
response_model = None
|
||||
else:
|
||||
response_model = return_annotation
|
||||
self.response_model = response_model
|
||||
self.summary = summary
|
||||
self.response_description = response_description
|
||||
@@ -517,6 +522,25 @@ class APIRouter(routing.Router):
|
||||
self.default_response_class = default_response_class
|
||||
self.generate_unique_id_function = generate_unique_id_function
|
||||
|
||||
def route(
|
||||
self,
|
||||
path: str,
|
||||
methods: Optional[List[str]] = None,
|
||||
name: Optional[str] = None,
|
||||
include_in_schema: bool = True,
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
def decorator(func: DecoratedCallable) -> DecoratedCallable:
|
||||
self.add_route(
|
||||
path,
|
||||
func,
|
||||
methods=methods,
|
||||
name=name,
|
||||
include_in_schema=include_in_schema,
|
||||
)
|
||||
return func
|
||||
|
||||
return decorator
|
||||
|
||||
def add_api_route(
|
||||
self,
|
||||
path: str,
|
||||
@@ -681,6 +705,15 @@ class APIRouter(routing.Router):
|
||||
|
||||
return decorator
|
||||
|
||||
def websocket_route(
|
||||
self, path: str, name: Union[str, None] = None
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
def decorator(func: DecoratedCallable) -> DecoratedCallable:
|
||||
self.add_websocket_route(path, func, name=name)
|
||||
return func
|
||||
|
||||
return decorator
|
||||
|
||||
def include_router(
|
||||
self,
|
||||
router: "APIRouter",
|
||||
@@ -1242,3 +1275,12 @@ class APIRouter(routing.Router):
|
||||
openapi_extra=openapi_extra,
|
||||
generate_unique_id_function=generate_unique_id_function,
|
||||
)
|
||||
|
||||
def on_event(
|
||||
self, event_type: str
|
||||
) -> Callable[[DecoratedCallable], DecoratedCallable]:
|
||||
def decorator(func: DecoratedCallable) -> DecoratedCallable:
|
||||
self.add_event_handler(event_type, func)
|
||||
return func
|
||||
|
||||
return decorator
|
||||
|
||||
@@ -88,7 +88,13 @@ def create_response_field(
|
||||
return response_field(field_info=field_info)
|
||||
except RuntimeError:
|
||||
raise fastapi.exceptions.FastAPIError(
|
||||
f"Invalid args for response field! Hint: check that {type_} is a valid pydantic field type"
|
||||
"Invalid args for response field! Hint: "
|
||||
f"check that {type_} is a valid Pydantic field type. "
|
||||
"If you are using a return type annotation that is not a valid Pydantic "
|
||||
"field (e.g. Union[Response, dict, None]) you can disable generating the "
|
||||
"response model from the type annotation with the path operation decorator "
|
||||
"parameter response_model=None. Read more: "
|
||||
"https://fastapi.tiangolo.com/tutorial/response-model/"
|
||||
) from None
|
||||
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ classifiers = [
|
||||
"Topic :: Internet :: WWW/HTTP",
|
||||
]
|
||||
dependencies = [
|
||||
"starlette==0.22.0",
|
||||
"starlette>=0.22.0,<=0.23.0",
|
||||
"pydantic >=1.6.2,!=1.7,!=1.7.1,!=1.7.2,!=1.7.3,!=1.8,!=1.8.1,<2.0.0",
|
||||
]
|
||||
dynamic = ["version"]
|
||||
@@ -155,6 +155,10 @@ source = [
|
||||
"fastapi"
|
||||
]
|
||||
context = '${CONTEXT}'
|
||||
omit = [
|
||||
"docs_src/response_model/tutorial003_04.py",
|
||||
"docs_src/response_model/tutorial003_04_py310.py",
|
||||
]
|
||||
|
||||
[tool.ruff]
|
||||
select = [
|
||||
|
||||
@@ -2,6 +2,8 @@ from typing import List, Union
|
||||
|
||||
import pytest
|
||||
from fastapi import FastAPI
|
||||
from fastapi.exceptions import FastAPIError
|
||||
from fastapi.responses import JSONResponse, Response
|
||||
from fastapi.testclient import TestClient
|
||||
from pydantic import BaseModel, ValidationError
|
||||
|
||||
@@ -237,6 +239,16 @@ def no_response_model_annotation_union_return_model2() -> Union[User, Item]:
|
||||
return Item(name="Foo", price=42.0)
|
||||
|
||||
|
||||
@app.get("/no_response_model-annotation_response_class")
|
||||
def no_response_model_annotation_response_class() -> Response:
|
||||
return Response(content="Foo")
|
||||
|
||||
|
||||
@app.get("/no_response_model-annotation_json_response_class")
|
||||
def no_response_model_annotation_json_response_class() -> JSONResponse:
|
||||
return JSONResponse(content={"foo": "bar"})
|
||||
|
||||
|
||||
openapi_schema = {
|
||||
"openapi": "3.0.2",
|
||||
"info": {"title": "FastAPI", "version": "0.1.0"},
|
||||
@@ -789,6 +801,30 @@ openapi_schema = {
|
||||
},
|
||||
}
|
||||
},
|
||||
"/no_response_model-annotation_response_class": {
|
||||
"get": {
|
||||
"summary": "No Response Model Annotation Response Class",
|
||||
"operationId": "no_response_model_annotation_response_class_no_response_model_annotation_response_class_get",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {"application/json": {"schema": {}}},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
"/no_response_model-annotation_json_response_class": {
|
||||
"get": {
|
||||
"summary": "No Response Model Annotation Json Response Class",
|
||||
"operationId": "no_response_model_annotation_json_response_class_no_response_model_annotation_json_response_class_get",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {"application/json": {"schema": {}}},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
@@ -1049,3 +1085,27 @@ def test_no_response_model_annotation_union_return_model2():
|
||||
response = client.get("/no_response_model-annotation_union-return_model2")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {"name": "Foo", "price": 42.0}
|
||||
|
||||
|
||||
def test_no_response_model_annotation_return_class():
|
||||
response = client.get("/no_response_model-annotation_response_class")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.text == "Foo"
|
||||
|
||||
|
||||
def test_no_response_model_annotation_json_response_class():
|
||||
response = client.get("/no_response_model-annotation_json_response_class")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {"foo": "bar"}
|
||||
|
||||
|
||||
def test_invalid_response_model_field():
|
||||
app = FastAPI()
|
||||
with pytest.raises(FastAPIError) as e:
|
||||
|
||||
@app.get("/")
|
||||
def read_root() -> Union[Response, None]:
|
||||
return Response(content="Foo") # pragma: no cover
|
||||
|
||||
assert "valid Pydantic field type" in e.value.args[0]
|
||||
assert "parameter response_model=None" in e.value.args[0]
|
||||
|
||||
@@ -46,5 +46,5 @@ def test_websocket():
|
||||
|
||||
def test_websocket_invalid_path_doesnt_match():
|
||||
with pytest.raises(WebSocketDisconnect):
|
||||
with client.websocket_connect("/itemsx/portal-gun") as websocket:
|
||||
websocket.receive_json()
|
||||
with client.websocket_connect("/itemsx/portal-gun"):
|
||||
pass
|
||||
|
||||
120
tests/test_tutorial/test_response_model/test_tutorial003_01.py
Normal file
120
tests/test_tutorial/test_response_model/test_tutorial003_01.py
Normal file
@@ -0,0 +1,120 @@
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.response_model.tutorial003_01 import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
openapi_schema = {
|
||||
"openapi": "3.0.2",
|
||||
"info": {"title": "FastAPI", "version": "0.1.0"},
|
||||
"paths": {
|
||||
"/user/": {
|
||||
"post": {
|
||||
"summary": "Create User",
|
||||
"operationId": "create_user_user__post",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/UserIn"}
|
||||
}
|
||||
},
|
||||
"required": True,
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/BaseUser"}
|
||||
}
|
||||
},
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"BaseUser": {
|
||||
"title": "BaseUser",
|
||||
"required": ["username", "email"],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {"title": "Username", "type": "string"},
|
||||
"email": {"title": "Email", "type": "string", "format": "email"},
|
||||
"full_name": {"title": "Full Name", "type": "string"},
|
||||
},
|
||||
},
|
||||
"HTTPValidationError": {
|
||||
"title": "HTTPValidationError",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {
|
||||
"title": "Detail",
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/components/schemas/ValidationError"},
|
||||
}
|
||||
},
|
||||
},
|
||||
"UserIn": {
|
||||
"title": "UserIn",
|
||||
"required": ["username", "email", "password"],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {"title": "Username", "type": "string"},
|
||||
"email": {"title": "Email", "type": "string", "format": "email"},
|
||||
"full_name": {"title": "Full Name", "type": "string"},
|
||||
"password": {"title": "Password", "type": "string"},
|
||||
},
|
||||
},
|
||||
"ValidationError": {
|
||||
"title": "ValidationError",
|
||||
"required": ["loc", "msg", "type"],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_openapi_schema():
|
||||
response = client.get("/openapi.json")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == openapi_schema
|
||||
|
||||
|
||||
def test_post_user():
|
||||
response = client.post(
|
||||
"/user/",
|
||||
json={
|
||||
"username": "foo",
|
||||
"password": "fighter",
|
||||
"email": "foo@example.com",
|
||||
"full_name": "Grave Dohl",
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {
|
||||
"username": "foo",
|
||||
"email": "foo@example.com",
|
||||
"full_name": "Grave Dohl",
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py310
|
||||
|
||||
openapi_schema = {
|
||||
"openapi": "3.0.2",
|
||||
"info": {"title": "FastAPI", "version": "0.1.0"},
|
||||
"paths": {
|
||||
"/user/": {
|
||||
"post": {
|
||||
"summary": "Create User",
|
||||
"operationId": "create_user_user__post",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/UserIn"}
|
||||
}
|
||||
},
|
||||
"required": True,
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {"$ref": "#/components/schemas/BaseUser"}
|
||||
}
|
||||
},
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"BaseUser": {
|
||||
"title": "BaseUser",
|
||||
"required": ["username", "email"],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {"title": "Username", "type": "string"},
|
||||
"email": {"title": "Email", "type": "string", "format": "email"},
|
||||
"full_name": {"title": "Full Name", "type": "string"},
|
||||
},
|
||||
},
|
||||
"HTTPValidationError": {
|
||||
"title": "HTTPValidationError",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {
|
||||
"title": "Detail",
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/components/schemas/ValidationError"},
|
||||
}
|
||||
},
|
||||
},
|
||||
"UserIn": {
|
||||
"title": "UserIn",
|
||||
"required": ["username", "email", "password"],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"username": {"title": "Username", "type": "string"},
|
||||
"email": {"title": "Email", "type": "string", "format": "email"},
|
||||
"full_name": {"title": "Full Name", "type": "string"},
|
||||
"password": {"title": "Password", "type": "string"},
|
||||
},
|
||||
},
|
||||
"ValidationError": {
|
||||
"title": "ValidationError",
|
||||
"required": ["loc", "msg", "type"],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
def get_client():
|
||||
from docs_src.response_model.tutorial003_01_py310 import app
|
||||
|
||||
client = TestClient(app)
|
||||
return client
|
||||
|
||||
|
||||
@needs_py310
|
||||
def test_openapi_schema(client: TestClient):
|
||||
response = client.get("/openapi.json")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == openapi_schema
|
||||
|
||||
|
||||
@needs_py310
|
||||
def test_post_user(client: TestClient):
|
||||
response = client.post(
|
||||
"/user/",
|
||||
json={
|
||||
"username": "foo",
|
||||
"password": "fighter",
|
||||
"email": "foo@example.com",
|
||||
"full_name": "Grave Dohl",
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {
|
||||
"username": "foo",
|
||||
"email": "foo@example.com",
|
||||
"full_name": "Grave Dohl",
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.response_model.tutorial003_02 import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
openapi_schema = {
|
||||
"openapi": "3.0.2",
|
||||
"info": {"title": "FastAPI", "version": "0.1.0"},
|
||||
"paths": {
|
||||
"/portal": {
|
||||
"get": {
|
||||
"summary": "Get Portal",
|
||||
"operationId": "get_portal_portal_get",
|
||||
"parameters": [
|
||||
{
|
||||
"required": False,
|
||||
"schema": {
|
||||
"title": "Teleport",
|
||||
"type": "boolean",
|
||||
"default": False,
|
||||
},
|
||||
"name": "teleport",
|
||||
"in": "query",
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {"application/json": {"schema": {}}},
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"HTTPValidationError": {
|
||||
"title": "HTTPValidationError",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {
|
||||
"title": "Detail",
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/components/schemas/ValidationError"},
|
||||
}
|
||||
},
|
||||
},
|
||||
"ValidationError": {
|
||||
"title": "ValidationError",
|
||||
"required": ["loc", "msg", "type"],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_openapi_schema():
|
||||
response = client.get("/openapi.json")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == openapi_schema
|
||||
|
||||
|
||||
def test_get_portal():
|
||||
response = client.get("/portal")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {"message": "Here's your interdimensional portal."}
|
||||
|
||||
|
||||
def test_get_redirect():
|
||||
response = client.get("/portal", params={"teleport": True}, follow_redirects=False)
|
||||
assert response.status_code == 307, response.text
|
||||
assert response.headers["location"] == "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
||||
@@ -0,0 +1,36 @@
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.response_model.tutorial003_03 import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
openapi_schema = {
|
||||
"openapi": "3.0.2",
|
||||
"info": {"title": "FastAPI", "version": "0.1.0"},
|
||||
"paths": {
|
||||
"/teleport": {
|
||||
"get": {
|
||||
"summary": "Get Teleport",
|
||||
"operationId": "get_teleport_teleport_get",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {"application/json": {"schema": {}}},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_openapi_schema():
|
||||
response = client.get("/openapi.json")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == openapi_schema
|
||||
|
||||
|
||||
def test_get_portal():
|
||||
response = client.get("/teleport", follow_redirects=False)
|
||||
assert response.status_code == 307, response.text
|
||||
assert response.headers["location"] == "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
||||
@@ -0,0 +1,9 @@
|
||||
import pytest
|
||||
from fastapi.exceptions import FastAPIError
|
||||
|
||||
|
||||
def test_invalid_response_model():
|
||||
with pytest.raises(FastAPIError):
|
||||
from docs_src.response_model.tutorial003_04 import app
|
||||
|
||||
assert app # pragma: no cover
|
||||
@@ -0,0 +1,12 @@
|
||||
import pytest
|
||||
from fastapi.exceptions import FastAPIError
|
||||
|
||||
from ...utils import needs_py310
|
||||
|
||||
|
||||
@needs_py310
|
||||
def test_invalid_response_model():
|
||||
with pytest.raises(FastAPIError):
|
||||
from docs_src.response_model.tutorial003_04_py310 import app
|
||||
|
||||
assert app # pragma: no cover
|
||||
@@ -0,0 +1,93 @@
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from docs_src.response_model.tutorial003_05 import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
openapi_schema = {
|
||||
"openapi": "3.0.2",
|
||||
"info": {"title": "FastAPI", "version": "0.1.0"},
|
||||
"paths": {
|
||||
"/portal": {
|
||||
"get": {
|
||||
"summary": "Get Portal",
|
||||
"operationId": "get_portal_portal_get",
|
||||
"parameters": [
|
||||
{
|
||||
"required": False,
|
||||
"schema": {
|
||||
"title": "Teleport",
|
||||
"type": "boolean",
|
||||
"default": False,
|
||||
},
|
||||
"name": "teleport",
|
||||
"in": "query",
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {"application/json": {"schema": {}}},
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"HTTPValidationError": {
|
||||
"title": "HTTPValidationError",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {
|
||||
"title": "Detail",
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/components/schemas/ValidationError"},
|
||||
}
|
||||
},
|
||||
},
|
||||
"ValidationError": {
|
||||
"title": "ValidationError",
|
||||
"required": ["loc", "msg", "type"],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_openapi_schema():
|
||||
response = client.get("/openapi.json")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == openapi_schema
|
||||
|
||||
|
||||
def test_get_portal():
|
||||
response = client.get("/portal")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {"message": "Here's your interdimensional portal."}
|
||||
|
||||
|
||||
def test_get_redirect():
|
||||
response = client.get("/portal", params={"teleport": True}, follow_redirects=False)
|
||||
assert response.status_code == 307, response.text
|
||||
assert response.headers["location"] == "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
||||
@@ -0,0 +1,103 @@
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py310
|
||||
|
||||
openapi_schema = {
|
||||
"openapi": "3.0.2",
|
||||
"info": {"title": "FastAPI", "version": "0.1.0"},
|
||||
"paths": {
|
||||
"/portal": {
|
||||
"get": {
|
||||
"summary": "Get Portal",
|
||||
"operationId": "get_portal_portal_get",
|
||||
"parameters": [
|
||||
{
|
||||
"required": False,
|
||||
"schema": {
|
||||
"title": "Teleport",
|
||||
"type": "boolean",
|
||||
"default": False,
|
||||
},
|
||||
"name": "teleport",
|
||||
"in": "query",
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {"application/json": {"schema": {}}},
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"HTTPValidationError": {
|
||||
"title": "HTTPValidationError",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {
|
||||
"title": "Detail",
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/components/schemas/ValidationError"},
|
||||
}
|
||||
},
|
||||
},
|
||||
"ValidationError": {
|
||||
"title": "ValidationError",
|
||||
"required": ["loc", "msg", "type"],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"anyOf": [{"type": "string"}, {"type": "integer"}]},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
def get_client():
|
||||
from docs_src.response_model.tutorial003_05_py310 import app
|
||||
|
||||
client = TestClient(app)
|
||||
return client
|
||||
|
||||
|
||||
@needs_py310
|
||||
def test_openapi_schema(client: TestClient):
|
||||
response = client.get("/openapi.json")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == openapi_schema
|
||||
|
||||
|
||||
@needs_py310
|
||||
def test_get_portal(client: TestClient):
|
||||
response = client.get("/portal")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {"message": "Here's your interdimensional portal."}
|
||||
|
||||
|
||||
@needs_py310
|
||||
def test_get_redirect(client: TestClient):
|
||||
response = client.get("/portal", params={"teleport": True}, follow_redirects=False)
|
||||
assert response.status_code == 307, response.text
|
||||
assert response.headers["location"] == "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
|
||||
Reference in New Issue
Block a user