diff --git a/.github/workflows/people.yml b/.github/workflows/people.yml index 11931a05a..c1df3455e 100644 --- a/.github/workflows/people.yml +++ b/.github/workflows/people.yml @@ -51,3 +51,4 @@ jobs: run: python ./scripts/people.py env: GITHUB_TOKEN: ${{ secrets.FASTAPI_PEOPLE }} + SLEEP_INTERVAL: ${{ vars.PEOPLE_SLEEP_INTERVAL }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7af88b5aa..680cafce9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,7 +14,7 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.11.13 + rev: v0.12.2 hooks: - id: ruff args: diff --git a/README.md b/README.md index 44fa2d3ac..25a1d9179 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ The key features are: - + @@ -470,15 +470,20 @@ Used by Starlette: * jinja2 - Required if you want to use the default template configuration. * python-multipart - Required if you want to support form "parsing", with `request.form()`. -Used by FastAPI / Starlette: +Used by FastAPI: * uvicorn - for the server that loads and serves your application. This includes `uvicorn[standard]`, which includes some dependencies (e.g. `uvloop`) needed for high performance serving. -* `fastapi-cli` - to provide the `fastapi` command. +* `fastapi-cli[standard]` - to provide the `fastapi` command. + * This includes `fastapi-cloud-cli`, which allows you to deploy your FastAPI application to FastAPI Cloud. ### Without `standard` Dependencies If you don't want to include the `standard` optional dependencies, you can install with `pip install fastapi` instead of `pip install "fastapi[standard]"`. +### Without `fastapi-cloud-cli` + +If you want to install FastAPI with the standard dependencies but without the `fastapi-cloud-cli`, you can install with `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. + ### Additional Optional Dependencies There are some additional dependencies you might want to install. diff --git a/docs/bn/docs/about/index.md b/docs/bn/docs/about/index.md new file mode 100644 index 000000000..b6d611ae9 --- /dev/null +++ b/docs/bn/docs/about/index.md @@ -0,0 +1,3 @@ +# সম্পর্কে + +**FastAPI** সম্পর্কে বিস্তারিত — এর ডিজাইন, অনুপ্রেরণা ও আরও অনেক কিছু। 🤓 diff --git a/docs/de/docs/advanced/generate-clients.md b/docs/de/docs/advanced/generate-clients.md index 38a69031c..f491d29af 100644 --- a/docs/de/docs/advanced/generate-clients.md +++ b/docs/de/docs/advanced/generate-clients.md @@ -20,7 +20,7 @@ Einige von diesen ✨ [**sponsern FastAPI**](../help-fastapi.md#den-autor-sponse Und es zeigt deren wahres Engagement für FastAPI und seine **Community** (Sie), da diese Ihnen nicht nur einen **guten Service** bieten möchten, sondern auch sicherstellen möchten, dass Sie über ein **gutes und gesundes Framework** verfügen, FastAPI. 🙇 -Beispielsweise könnten Sie Speakeasy ausprobieren. +Beispielsweise könnten Sie Speakeasy ausprobieren. Es gibt auch mehrere andere Unternehmen, welche ähnliche Dienste anbieten und die Sie online suchen und finden können. 🤓 diff --git a/docs/en/data/contributors.yml b/docs/en/data/contributors.yml index f3f7c9133..e06510ac4 100644 --- a/docs/en/data/contributors.yml +++ b/docs/en/data/contributors.yml @@ -1,11 +1,11 @@ tiangolo: login: tiangolo - count: 747 + count: 753 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4 url: https://github.com/tiangolo dependabot: login: dependabot - count: 102 + count: 104 avatarUrl: https://avatars.githubusercontent.com/in/29110?v=4 url: https://github.com/apps/dependabot alejsdev: @@ -15,7 +15,7 @@ alejsdev: url: https://github.com/alejsdev pre-commit-ci: login: pre-commit-ci - count: 30 + count: 33 avatarUrl: https://avatars.githubusercontent.com/in/68672?v=4 url: https://github.com/apps/pre-commit-ci github-actions: @@ -116,7 +116,7 @@ hitrust: ShahriyarR: login: ShahriyarR count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/3852029?u=c9a1691e5ebdc94cbf543086099a6ed705cdb873&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/3852029?u=631b2ae59360ab380c524b32bc3d245aff1165af&v=4 url: https://github.com/ShahriyarR adriangb: login: adriangb @@ -513,6 +513,11 @@ tamird: count: 2 avatarUrl: https://avatars.githubusercontent.com/u/1535036?v=4 url: https://github.com/tamird +ndimares: + login: ndimares + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/6267663?u=cfb27efde7a7212be8142abb6c058a1aeadb41b1&v=4 + url: https://github.com/ndimares rabinlamadong: login: rabinlamadong count: 2 @@ -538,8 +543,18 @@ DanielYang59: count: 2 avatarUrl: https://avatars.githubusercontent.com/u/80093591?u=63873f701c7c74aac83c906800a1dddc0bc8c92f&v=4 url: https://github.com/DanielYang59 +valentinDruzhinin: + login: valentinDruzhinin + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4 + url: https://github.com/valentinDruzhinin blueswen: login: blueswen count: 2 avatarUrl: https://avatars.githubusercontent.com/u/1564148?u=6d6b8cc8f2b5cef715e68d6175154a8a94d518ee&v=4 url: https://github.com/blueswen +YuriiMotov: + login: YuriiMotov + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=e83a39697a2d33ab2ec9bfbced794ee48bc29cec&v=4 + url: https://github.com/YuriiMotov diff --git a/docs/en/data/github_sponsors.yml b/docs/en/data/github_sponsors.yml index efc5cbfcc..0cb200185 100644 --- a/docs/en/data/github_sponsors.yml +++ b/docs/en/data/github_sponsors.yml @@ -1,10 +1,10 @@ sponsors: +- - login: classmethod + avatarUrl: https://avatars.githubusercontent.com/u/1532151?v=4 + url: https://github.com/classmethod - - login: renderinc avatarUrl: https://avatars.githubusercontent.com/u/36424661?v=4 url: https://github.com/renderinc - - login: Nixtla - avatarUrl: https://avatars.githubusercontent.com/u/79945230?v=4 - url: https://github.com/Nixtla - login: andrew-propelauth avatarUrl: https://avatars.githubusercontent.com/u/89474256?u=c98993dec8553c09d424ede67bbe86e5c35f48c9&v=4 url: https://github.com/andrew-propelauth @@ -17,12 +17,15 @@ sponsors: - login: coderabbitai avatarUrl: https://avatars.githubusercontent.com/u/132028505?v=4 url: https://github.com/coderabbitai + - login: madisonredtfeldt + avatarUrl: https://avatars.githubusercontent.com/u/152656511?v=4 + url: https://github.com/madisonredtfeldt - login: subtotal avatarUrl: https://avatars.githubusercontent.com/u/176449348?v=4 url: https://github.com/subtotal - - login: porter-dev - avatarUrl: https://avatars.githubusercontent.com/u/62078005?v=4 - url: https://github.com/porter-dev + - login: Nixtla + avatarUrl: https://avatars.githubusercontent.com/u/79945230?v=4 + url: https://github.com/Nixtla - login: scalar avatarUrl: https://avatars.githubusercontent.com/u/301879?v=4 url: https://github.com/scalar @@ -41,27 +44,27 @@ sponsors: - login: speakeasy-api avatarUrl: https://avatars.githubusercontent.com/u/91446104?v=4 url: https://github.com/speakeasy-api - - login: snapit-cypher - avatarUrl: https://avatars.githubusercontent.com/u/115662654?v=4 - url: https://github.com/snapit-cypher - login: databento avatarUrl: https://avatars.githubusercontent.com/u/64141749?v=4 url: https://github.com/databento - login: permitio avatarUrl: https://avatars.githubusercontent.com/u/71775833?v=4 url: https://github.com/permitio -- - login: mercedes-benz - avatarUrl: https://avatars.githubusercontent.com/u/34240465?v=4 - url: https://github.com/mercedes-benz - - login: xoflare +- - login: xoflare avatarUrl: https://avatars.githubusercontent.com/u/74335107?v=4 url: https://github.com/xoflare - login: marvin-robot avatarUrl: https://avatars.githubusercontent.com/u/41086007?u=b9fcab402d0cd0aec738b6574fe60855cb0cd36d&v=4 url: https://github.com/marvin-robot + - login: mercedes-benz + avatarUrl: https://avatars.githubusercontent.com/u/34240465?v=4 + url: https://github.com/mercedes-benz - login: Ponte-Energy-Partners avatarUrl: https://avatars.githubusercontent.com/u/114745848?v=4 url: https://github.com/Ponte-Energy-Partners + - login: snapit-cypher + avatarUrl: https://avatars.githubusercontent.com/u/115662654?v=4 + url: https://github.com/snapit-cypher - login: LambdaTest-Inc avatarUrl: https://avatars.githubusercontent.com/u/171592363?u=96606606a45fa170427206199014f2a5a2a4920b&v=4 url: https://github.com/LambdaTest-Inc @@ -98,15 +101,21 @@ sponsors: - - login: samuelcolvin avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=42eb3b833047c8c4b4f647a031eaef148c16d93f&v=4 url: https://github.com/samuelcolvin + - login: CoodingPenguin + avatarUrl: https://avatars.githubusercontent.com/u/37505775?u=6a9e1f6647fbf95f99afeee82a3682e15fc6e959&v=4 + url: https://github.com/CoodingPenguin + - login: deight93 + avatarUrl: https://avatars.githubusercontent.com/u/37678115?u=a608798b5bd0034183a9c430ebb42fb266db86ce&v=4 + url: https://github.com/deight93 - login: otosky avatarUrl: https://avatars.githubusercontent.com/u/42260747?u=69d089387c743d89427aa4ad8740cfb34045a9e0&v=4 url: https://github.com/otosky - login: ramonalmeidam avatarUrl: https://avatars.githubusercontent.com/u/45269580?u=3358750b3a5854d7c3ed77aaca7dd20a0f529d32&v=4 url: https://github.com/ramonalmeidam - - login: ashi-agrawal - avatarUrl: https://avatars.githubusercontent.com/u/17105294?u=99c7a854035e5398d8e7b674f2d42baae6c957f8&v=4 - url: https://github.com/ashi-agrawal + - login: kaoru0310 + avatarUrl: https://avatars.githubusercontent.com/u/80977929?u=1b61d10142b490e56af932ddf08a390fae8ee94f&v=4 + url: https://github.com/kaoru0310 - login: RaamEEIL avatarUrl: https://avatars.githubusercontent.com/u/20320552?v=4 url: https://github.com/RaamEEIL @@ -125,9 +134,6 @@ sponsors: - login: ProteinQure avatarUrl: https://avatars.githubusercontent.com/u/33707203?v=4 url: https://github.com/ProteinQure - - login: kaoru0310 - avatarUrl: https://avatars.githubusercontent.com/u/80977929?u=1b61d10142b490e56af932ddf08a390fae8ee94f&v=4 - url: https://github.com/kaoru0310 - login: DelfinaCare avatarUrl: https://avatars.githubusercontent.com/u/83734439?v=4 url: https://github.com/DelfinaCare @@ -191,9 +197,6 @@ sponsors: - login: gorhack avatarUrl: https://avatars.githubusercontent.com/u/4141690?u=ec119ebc4bdf00a7bc84657a71aa17834f4f27f3&v=4 url: https://github.com/gorhack - - login: Ryandaydev - avatarUrl: https://avatars.githubusercontent.com/u/4292423?u=679ff84cb7b988c5795a5fa583857f574a055763&v=4 - url: https://github.com/Ryandaydev - login: vincentkoc avatarUrl: https://avatars.githubusercontent.com/u/25068?u=fbd5b2d51142daa4bdbc21e21953a3b8b8188a4a&v=4 url: https://github.com/vincentkoc @@ -227,15 +230,9 @@ sponsors: - login: mintuhouse avatarUrl: https://avatars.githubusercontent.com/u/769950?u=ecfbd79a97d33177e0d093ddb088283cf7fe8444&v=4 url: https://github.com/mintuhouse - - login: TrevorBenson - avatarUrl: https://avatars.githubusercontent.com/u/9167887?u=dccbea3327a57750923333d8ebf1a0b3f1948949&v=4 - url: https://github.com/TrevorBenson - login: wdwinslow - avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=dc01daafb354135603a263729e3d26d939c0c452&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=371272f2c69e680e0559a7b0a57385e83a5dc728&v=4 url: https://github.com/wdwinslow - - login: catherinenelson1 - avatarUrl: https://avatars.githubusercontent.com/u/11951946?u=fe11bc35d36b6038cd46a946e4e46ef8aa5688ab&v=4 - url: https://github.com/catherinenelson1 - login: jsoques avatarUrl: https://avatars.githubusercontent.com/u/12414216?u=620921d94196546cc8b9eae2cc4cbc3f95bab42f&v=4 url: https://github.com/jsoques @@ -251,6 +248,12 @@ sponsors: - login: mjohnsey avatarUrl: https://avatars.githubusercontent.com/u/16784016?u=38fad2e6b411244560b3af99c5f5a4751bc81865&v=4 url: https://github.com/mjohnsey + - login: ashi-agrawal + avatarUrl: https://avatars.githubusercontent.com/u/17105294?u=99c7a854035e5398d8e7b674f2d42baae6c957f8&v=4 + url: https://github.com/ashi-agrawal + - login: Ryandaydev + avatarUrl: https://avatars.githubusercontent.com/u/4292423?u=679ff84cb7b988c5795a5fa583857f574a055763&v=4 + url: https://github.com/Ryandaydev - login: jaredtrog avatarUrl: https://avatars.githubusercontent.com/u/4381365?v=4 url: https://github.com/jaredtrog @@ -278,9 +281,6 @@ sponsors: - - login: pawamoy avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4 url: https://github.com/pawamoy - - login: bnkc - avatarUrl: https://avatars.githubusercontent.com/u/34930566?u=db5e6f4f87836cad26c2aa90ce390ce49041c5a9&v=4 - url: https://github.com/bnkc - login: petercool avatarUrl: https://avatars.githubusercontent.com/u/37613029?u=81c525232bb35780945a68e88afd96bb2cdad9c4&v=4 url: https://github.com/petercool @@ -296,12 +296,6 @@ sponsors: - login: caviri avatarUrl: https://avatars.githubusercontent.com/u/45425937?u=4e14bd64282bad8f385eafbdb004b5a279366d6e&v=4 url: https://github.com/caviri - - login: hgalytoby - avatarUrl: https://avatars.githubusercontent.com/u/50397689?u=62c7ff3519858423579676cd0efbd7e3f1ffe63a&v=4 - url: https://github.com/hgalytoby - - login: browniebroke - avatarUrl: https://avatars.githubusercontent.com/u/861044?u=5abfca5588f3e906b31583d7ee62f6de4b68aa24&v=4 - url: https://github.com/browniebroke - login: joshuatz avatarUrl: https://avatars.githubusercontent.com/u/17817563?u=f1bf05b690d1fc164218f0b420cdd3acb7913e21&v=4 url: https://github.com/joshuatz @@ -323,21 +317,24 @@ sponsors: - login: engineerjoe440 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=db5e6f4f87836cad26c2aa90ce390ce49041c5a9&v=4 + url: https://github.com/bnkc - login: lukzmu - avatarUrl: https://avatars.githubusercontent.com/u/175964415?u=83ea9b0b7b7b0f15bcb5747d93f303447a19a00b&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/175964415?u=75348f25bb99a5f92ddb40c0b9b1ff7acb39c150&v=4 url: https://github.com/lukzmu - - login: conservative-dude - avatarUrl: https://avatars.githubusercontent.com/u/55538308?u=f250c44942ea6e73a6bd90739b381c470c192c11&v=4 - url: https://github.com/conservative-dude - - login: CR1337 - avatarUrl: https://avatars.githubusercontent.com/u/62649536?u=57a6aab10d2421a497306da8bcded01b826c54ae&v=4 - url: https://github.com/CR1337 + - login: hgalytoby + avatarUrl: https://avatars.githubusercontent.com/u/50397689?u=62c7ff3519858423579676cd0efbd7e3f1ffe63a&v=4 + url: https://github.com/hgalytoby - login: PunRabbit avatarUrl: https://avatars.githubusercontent.com/u/70463212?u=1a835cfbc99295a60c8282f6aa6199d1b42241a5&v=4 url: https://github.com/PunRabbit - login: PelicanQ avatarUrl: https://avatars.githubusercontent.com/u/77930606?v=4 url: https://github.com/PelicanQ + - login: browniebroke + avatarUrl: https://avatars.githubusercontent.com/u/861044?u=5abfca5588f3e906b31583d7ee62f6de4b68aa24&v=4 + url: https://github.com/browniebroke - login: miguelgr avatarUrl: https://avatars.githubusercontent.com/u/1484589?u=54556072b8136efa12ae3b6902032ea2a39ace4b&v=4 url: https://github.com/miguelgr @@ -347,9 +344,6 @@ sponsors: - login: my3 avatarUrl: https://avatars.githubusercontent.com/u/1825270?v=4 url: https://github.com/my3 - - login: leobiscassi - avatarUrl: https://avatars.githubusercontent.com/u/1977418?u=f9f82445a847ab479bd7223debd677fcac6c49a0&v=4 - url: https://github.com/leobiscassi - login: Alisa-lisa avatarUrl: https://avatars.githubusercontent.com/u/4137964?u=e7e393504f554f4ff15863a1e01a5746863ef9ce&v=4 url: https://github.com/Alisa-lisa @@ -425,9 +419,6 @@ sponsors: - login: harsh183 avatarUrl: https://avatars.githubusercontent.com/u/7780198?v=4 url: https://github.com/harsh183 - - login: hcristea - avatarUrl: https://avatars.githubusercontent.com/u/7814406?u=19092923a4ea5b338567961c8270b9206a6d81bb&v=4 - url: https://github.com/hcristea - - login: andrecorumba avatarUrl: https://avatars.githubusercontent.com/u/37807517?u=9b9be3b41da9bda60957da9ef37b50dbf65baa61&v=4 url: https://github.com/andrecorumba @@ -446,15 +437,21 @@ sponsors: - login: larsyngvelundin avatarUrl: https://avatars.githubusercontent.com/u/34173819?u=74958599695bf83ac9f1addd935a51548a10c6b0&v=4 url: https://github.com/larsyngvelundin - - login: one-st-one + - login: 0ne-stone avatarUrl: https://avatars.githubusercontent.com/u/62360849?u=746dd21c34e7e06eefb11b03e8bb01aaae3c2a4f&v=4 - url: https://github.com/one-st-one - - login: federicsp - avatarUrl: https://avatars.githubusercontent.com/u/62903636?u=05004f4a2c590f1d18c200e17978bf2e17acb632&v=4 - url: https://github.com/federicsp + url: https://github.com/0ne-stone + - login: darixsamani + avatarUrl: https://avatars.githubusercontent.com/u/67915678?u=cfa82128692eeeec4bf0e7a0faaa9a614695c0f9&v=4 + url: https://github.com/darixsamani + - login: nayasinghania + avatarUrl: https://avatars.githubusercontent.com/u/74111380?u=af853245a21fe052b6a27e41a8de8cf4cdf76e85&v=4 + url: https://github.com/nayasinghania - login: Toothwitch avatarUrl: https://avatars.githubusercontent.com/u/1710406?u=5eebb23b46cd26e48643b9e5179536cad491c17a&v=4 url: https://github.com/Toothwitch + - login: roboman-tech + avatarUrl: https://avatars.githubusercontent.com/u/8183070?u=fdeaa2ed29f598eb7901693884c0ad32b16982e3&v=4 + url: https://github.com/roboman-tech - login: andreagrandi avatarUrl: https://avatars.githubusercontent.com/u/636391?u=13d90cb8ec313593a5b71fbd4e33b78d6da736f5&v=4 url: https://github.com/andreagrandi diff --git a/docs/en/data/people.yml b/docs/en/data/people.yml index a94c7c63c..e3eab5d01 100644 --- a/docs/en/data/people.yml +++ b/docs/en/data/people.yml @@ -8,22 +8,22 @@ experts: count: 1898 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4 url: https://github.com/tiangolo +- login: YuriiMotov + count: 941 + avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=e83a39697a2d33ab2ec9bfbced794ee48bc29cec&v=4 + url: https://github.com/YuriiMotov - login: github-actions - count: 770 + count: 769 avatarUrl: https://avatars.githubusercontent.com/in/15368?v=4 url: https://github.com/apps/github-actions - login: Kludex - count: 655 + count: 654 avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4 url: https://github.com/Kludex - login: jgould22 count: 263 avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 url: https://github.com/jgould22 -- login: YuriiMotov - count: 247 - avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=e83a39697a2d33ab2ec9bfbced794ee48bc29cec&v=4 - url: https://github.com/YuriiMotov - login: dmontagu count: 240 avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4 @@ -33,11 +33,11 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/1405026?v=4 url: https://github.com/Mause - login: ycd - count: 217 + count: 216 avatarUrl: https://avatars.githubusercontent.com/u/62724709?u=f1e7bae394a315da950912c92dc861a8eaf95d4c&v=4 url: https://github.com/ycd - login: JarroVGIT - count: 192 + count: 190 avatarUrl: https://avatars.githubusercontent.com/u/13659033?u=e8bea32d07a5ef72f7dde3b2079ceb714923ca05&v=4 url: https://github.com/JarroVGIT - login: euri10 @@ -53,65 +53,65 @@ experts: avatarUrl: https://avatars.githubusercontent.com/u/331403?v=4 url: https://github.com/phy25 - login: JavierSanchezCastro - count: 91 + count: 93 avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4 url: https://github.com/JavierSanchezCastro +- login: luzzodev + count: 84 + avatarUrl: https://avatars.githubusercontent.com/u/27291415?u=5607ae1ce75c5f54f09500ca854227f7bfd2033b&v=4 + url: https://github.com/luzzodev - login: raphaelauv count: 83 avatarUrl: https://avatars.githubusercontent.com/u/10202690?u=e6f86f5c0c3026a15d6b51792fa3e532b12f1371&v=4 url: https://github.com/raphaelauv -- login: ghandic - count: 71 - avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 - url: https://github.com/ghandic - login: ArcLightSlavik count: 71 avatarUrl: https://avatars.githubusercontent.com/u/31127044?u=b0f2c37142f4b762e41ad65dc49581813422bd71&v=4 url: https://github.com/ArcLightSlavik +- login: ghandic + count: 71 + avatarUrl: https://avatars.githubusercontent.com/u/23500353?u=e2e1d736f924d9be81e8bfc565b6d8836ba99773&v=4 + url: https://github.com/ghandic - login: n8sty count: 67 avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 url: https://github.com/n8sty -- login: luzzodev - count: 61 - avatarUrl: https://avatars.githubusercontent.com/u/27291415?u=5607ae1ce75c5f54f09500ca854227f7bfd2033b&v=4 - url: https://github.com/luzzodev - login: falkben count: 59 avatarUrl: https://avatars.githubusercontent.com/u/653031?u=ad9838e089058c9e5a0bab94c0eec7cc181e0cd0&v=4 url: https://github.com/falkben -- login: acidjunk - count: 50 - avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 - url: https://github.com/acidjunk - login: yinziyan1206 - count: 49 + count: 50 avatarUrl: https://avatars.githubusercontent.com/u/37829370?u=da44ca53aefd5c23f346fab8e9fd2e108294c179&v=4 url: https://github.com/yinziyan1206 - login: sm-Fifteen count: 49 avatarUrl: https://avatars.githubusercontent.com/u/516999?u=437c0c5038558c67e887ccd863c1ba0f846c03da&v=4 url: https://github.com/sm-Fifteen +- login: acidjunk + count: 49 + avatarUrl: https://avatars.githubusercontent.com/u/685002?u=b5094ab4527fc84b006c0ac9ff54367bdebb2267&v=4 + url: https://github.com/acidjunk - login: adriangb count: 46 avatarUrl: https://avatars.githubusercontent.com/u/1755071?u=612704256e38d6ac9cbed24f10e4b6ac2da74ecb&v=4 url: https://github.com/adriangb -- login: insomnes - count: 45 - avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4 - url: https://github.com/insomnes - login: Dustyposa count: 45 avatarUrl: https://avatars.githubusercontent.com/u/27180793?u=5cf2877f50b3eb2bc55086089a78a36f07042889&v=4 url: https://github.com/Dustyposa -- login: odiseo0 - count: 43 - avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=241a71f6b7068738b81af3e57f45ffd723538401&v=4 - url: https://github.com/odiseo0 +- login: insomnes + count: 45 + avatarUrl: https://avatars.githubusercontent.com/u/16958893?u=f8be7088d5076d963984a21f95f44e559192d912&v=4 + url: https://github.com/insomnes - login: frankie567 count: 43 avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=c159fe047727aedecbbeeaa96a1b03ceb9d39add&v=4 url: https://github.com/frankie567 +- login: odiseo0 + count: 43 + avatarUrl: https://avatars.githubusercontent.com/u/87550035?u=241a71f6b7068738b81af3e57f45ffd723538401&v=4 + url: https://github.com/odiseo0 - login: sinisaos count: 41 avatarUrl: https://avatars.githubusercontent.com/u/30960668?v=4 @@ -120,14 +120,14 @@ experts: count: 40 avatarUrl: https://avatars.githubusercontent.com/u/11836741?u=8bd5ef7e62fe6a82055e33c4c0e0a7879ff8cfb6&v=4 url: https://github.com/includeamin -- login: chbndrhnns - count: 37 - avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 - url: https://github.com/chbndrhnns - login: STeveShary count: 37 avatarUrl: https://avatars.githubusercontent.com/u/5167622?u=de8f597c81d6336fcebc37b32dfd61a3f877160c&v=4 url: https://github.com/STeveShary +- login: chbndrhnns + count: 37 + avatarUrl: https://avatars.githubusercontent.com/u/7534547?v=4 + url: https://github.com/chbndrhnns - login: krishnardt count: 35 avatarUrl: https://avatars.githubusercontent.com/u/31960541?u=47f4829c77f4962ab437ffb7995951e41eeebe9b&v=4 @@ -144,14 +144,14 @@ experts: count: 27 avatarUrl: https://avatars.githubusercontent.com/u/13135006?u=99f0b0f0fc47e88e8abb337b4447357939ef93e7&v=4 url: https://github.com/hasansezertasan +- login: alv2017 + count: 26 + avatarUrl: https://avatars.githubusercontent.com/u/31544722?v=4 + url: https://github.com/alv2017 - login: dbanty count: 26 avatarUrl: https://avatars.githubusercontent.com/u/43723790?u=9d726785d08e50b1e1cd96505800c8ea8405bce2&v=4 url: https://github.com/dbanty -- login: alv2017 - count: 25 - avatarUrl: https://avatars.githubusercontent.com/u/31544722?v=4 - url: https://github.com/alv2017 - login: wshayes count: 25 avatarUrl: https://avatars.githubusercontent.com/u/365303?u=07ca03c5ee811eb0920e633cc3c3db73dbec1aa5&v=4 @@ -176,10 +176,6 @@ experts: count: 21 avatarUrl: https://avatars.githubusercontent.com/u/51059348?u=5fe59a56e1f2f9ccd8005d71752a8276f133ae1a&v=4 url: https://github.com/rafsaf -- login: ebottos94 - count: 20 - avatarUrl: https://avatars.githubusercontent.com/u/100039558?u=8b91053b3abe4a9209375e3651e1c1ef192d884b&v=4 - url: https://github.com/ebottos94 - login: nsidnev count: 20 avatarUrl: https://avatars.githubusercontent.com/u/22559461?u=a9cc3238217e21dc8796a1a500f01b722adb082c&v=4 @@ -188,10 +184,18 @@ experts: count: 20 avatarUrl: https://avatars.githubusercontent.com/u/565544?v=4 url: https://github.com/chris-allnutt +- login: ebottos94 + count: 20 + avatarUrl: https://avatars.githubusercontent.com/u/100039558?u=8b91053b3abe4a9209375e3651e1c1ef192d884b&v=4 + url: https://github.com/ebottos94 - login: estebanx64 count: 19 avatarUrl: https://avatars.githubusercontent.com/u/10840422?u=45f015f95e1c0f06df602be4ab688d4b854cc8a8&v=4 url: https://github.com/estebanx64 +- login: retnikt + count: 18 + avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4 + url: https://github.com/retnikt - login: zoliknemet count: 18 avatarUrl: https://avatars.githubusercontent.com/u/22326718?u=31ba446ac290e23e56eea8e4f0c558aaf0b40779&v=4 @@ -200,14 +204,6 @@ experts: count: 18 avatarUrl: https://avatars.githubusercontent.com/u/14166324?u=8fac65e84dfff24245d304a5b5b09f7b5bd69dc9&v=4 url: https://github.com/sehraramiz -- login: retnikt - count: 18 - avatarUrl: https://avatars.githubusercontent.com/u/24581770?v=4 - url: https://github.com/retnikt -- login: caeser1996 - count: 17 - avatarUrl: https://avatars.githubusercontent.com/u/16540232?u=05d2beb8e034d584d0a374b99d8826327bd7f614&v=4 - url: https://github.com/caeser1996 - login: Hultner count: 17 avatarUrl: https://avatars.githubusercontent.com/u/2669034?u=115e53df959309898ad8dc9443fbb35fee71df07&v=4 @@ -216,197 +212,249 @@ experts: count: 17 avatarUrl: https://avatars.githubusercontent.com/u/1765494?u=5b1ab7c582db4b4016fa31affe977d10af108ad4&v=4 url: https://github.com/harunyasar +- login: caeser1996 + count: 17 + avatarUrl: https://avatars.githubusercontent.com/u/16540232?u=05d2beb8e034d584d0a374b99d8826327bd7f614&v=4 + url: https://github.com/caeser1996 - login: nkhitrov count: 17 avatarUrl: https://avatars.githubusercontent.com/u/28262306?u=e19427d8dc296d6950e9c424adacc92d37496fe9&v=4 url: https://github.com/nkhitrov -- login: jonatasoli - count: 16 - avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=f601c3f111f2148bd9244c2cb3ebbd57b592e674&v=4 - url: https://github.com/jonatasoli - login: dstlny count: 16 avatarUrl: https://avatars.githubusercontent.com/u/41964673?u=9f2174f9d61c15c6e3a4c9e3aeee66f711ce311f&v=4 url: https://github.com/dstlny -- login: abhint - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/25699289?u=b5d219277b4d001ac26fb8be357fddd88c29d51b&v=4 - url: https://github.com/abhint -- login: ceb10n +- login: jonatasoli + count: 16 + avatarUrl: https://avatars.githubusercontent.com/u/26334101?u=f601c3f111f2148bd9244c2cb3ebbd57b592e674&v=4 + url: https://github.com/jonatasoli +- login: ghost count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4 - url: https://github.com/ceb10n + avatarUrl: https://avatars.githubusercontent.com/u/10137?u=b1951d34a583cf12ec0d3b0781ba19be97726318&v=4 + url: https://github.com/ghost - login: jorgerpo count: 15 avatarUrl: https://avatars.githubusercontent.com/u/12537771?u=7444d20019198e34911082780cc7ad73f2b97cb3&v=4 url: https://github.com/jorgerpo -- login: simondale00 +- login: pythonweb2 + count: 15 + avatarUrl: https://avatars.githubusercontent.com/u/32141163?v=4 + url: https://github.com/pythonweb2 +- login: abhint count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/33907262?u=2721fb37014d50daf473267c808aa678ecaefe09&v=4 - url: https://github.com/simondale00 + avatarUrl: https://avatars.githubusercontent.com/u/25699289?u=b5d219277b4d001ac26fb8be357fddd88c29d51b&v=4 + url: https://github.com/abhint last_month_experts: - login: YuriiMotov - count: 9 + count: 289 avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=e83a39697a2d33ab2ec9bfbced794ee48bc29cec&v=4 url: https://github.com/YuriiMotov - login: luzzodev - count: 8 + count: 12 avatarUrl: https://avatars.githubusercontent.com/u/27291415?u=5607ae1ce75c5f54f09500ca854227f7bfd2033b&v=4 url: https://github.com/luzzodev -- login: alv2017 - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/31544722?v=4 - url: https://github.com/alv2017 +- login: raceychan + count: 6 + avatarUrl: https://avatars.githubusercontent.com/u/75417963?u=060c62870ec5a791765e63ac20d8885d11143786&v=4 + url: https://github.com/raceychan +- login: valentinDruzhinin + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4 + url: https://github.com/valentinDruzhinin +- login: DoctorJohn + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/14076775?u=2913e70a6142772847e91e2aaa5b9152391715e9&v=4 + url: https://github.com/DoctorJohn +- login: eqsdxr + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=58fddf77ed76966eaa8c73eea9bea4bb0c53b673&v=4 + url: https://github.com/eqsdxr - login: sachinh35 - count: 2 + count: 4 avatarUrl: https://avatars.githubusercontent.com/u/21972708?u=8560b97b8b41e175f476270b56de8a493b84f302&v=4 url: https://github.com/sachinh35 -- login: KianAnbarestani - count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/145364424?u=dcc3d8fb4ca07d36fb52a17f38b6650565de40be&v=4 - url: https://github.com/KianAnbarestani - login: tiangolo count: 2 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4 url: https://github.com/tiangolo +- login: Brikas + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/80290187?v=4 + url: https://github.com/Brikas +- login: TaigoFr + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/17792131?u=372b27056ec82f1ae03d8b3f37ef55b04a7cfdd1&v=4 + url: https://github.com/TaigoFr three_months_experts: -- login: luzzodev - count: 25 - avatarUrl: https://avatars.githubusercontent.com/u/27291415?u=5607ae1ce75c5f54f09500ca854227f7bfd2033b&v=4 - url: https://github.com/luzzodev - login: YuriiMotov - count: 24 + count: 732 avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=e83a39697a2d33ab2ec9bfbced794ee48bc29cec&v=4 url: https://github.com/YuriiMotov -- login: alv2017 - count: 22 - avatarUrl: https://avatars.githubusercontent.com/u/31544722?v=4 - url: https://github.com/alv2017 -- login: jgould22 - count: 13 - avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 - url: https://github.com/jgould22 -- login: Kludex - count: 10 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4 - url: https://github.com/Kludex -- login: yauhen-sobaleu - count: 9 - avatarUrl: https://avatars.githubusercontent.com/u/51629535?u=fc1817060daf2df438bfca86c44f33da5cd667db&v=4 - url: https://github.com/yauhen-sobaleu -- login: JavierSanchezCastro - count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4 - url: https://github.com/JavierSanchezCastro -- login: tiangolo - count: 6 - avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4 - url: https://github.com/tiangolo +- login: luzzodev + count: 26 + avatarUrl: https://avatars.githubusercontent.com/u/27291415?u=5607ae1ce75c5f54f09500ca854227f7bfd2033b&v=4 + url: https://github.com/luzzodev +- login: valentinDruzhinin + count: 14 + avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4 + url: https://github.com/valentinDruzhinin - login: sachinh35 - count: 3 + count: 8 avatarUrl: https://avatars.githubusercontent.com/u/21972708?u=8560b97b8b41e175f476270b56de8a493b84f302&v=4 url: https://github.com/sachinh35 -- login: SobikXexe - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/87701130?v=4 - url: https://github.com/SobikXexe -- login: KianAnbarestani +- login: raceychan + count: 6 + avatarUrl: https://avatars.githubusercontent.com/u/75417963?u=060c62870ec5a791765e63ac20d8885d11143786&v=4 + url: https://github.com/raceychan +- login: DoctorJohn + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/14076775?u=2913e70a6142772847e91e2aaa5b9152391715e9&v=4 + url: https://github.com/DoctorJohn +- login: eqsdxr + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=58fddf77ed76966eaa8c73eea9bea4bb0c53b673&v=4 + url: https://github.com/eqsdxr +- login: tiangolo count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/145364424?u=dcc3d8fb4ca07d36fb52a17f38b6650565de40be&v=4 - url: https://github.com/KianAnbarestani -- login: sinisaos + avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4 + url: https://github.com/tiangolo +- login: JavierSanchezCastro count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/30960668?v=4 - url: https://github.com/sinisaos -- login: Ale-Cas + avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4 + url: https://github.com/JavierSanchezCastro +- login: henrymcl count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/64859146?u=d52a6ecf8d83d2927e2ae270bdfcc83495dba8c9&v=4 - url: https://github.com/Ale-Cas -- login: adsouza + avatarUrl: https://avatars.githubusercontent.com/u/26480299?v=4 + url: https://github.com/henrymcl +- login: jymchng count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/275832?v=4 - url: https://github.com/adsouza -- login: marsboy02 + avatarUrl: https://avatars.githubusercontent.com/u/27895426?u=fb88c47775147d62a395fdb895d1af4148c7b566&v=4 + url: https://github.com/jymchng +- login: Brikas count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/86903678?u=fa4a6b91eea3a11ae93c162616ca5edf51c68572&v=4 - url: https://github.com/marsboy02 -- login: EverStarck + avatarUrl: https://avatars.githubusercontent.com/u/80290187?v=4 + url: https://github.com/Brikas +- login: TaigoFr count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/51029456?u=343409b7cb6b3ea6a59359f4e8370d9c3f140ecd&v=4 - url: https://github.com/EverStarck -- login: vtgn + avatarUrl: https://avatars.githubusercontent.com/u/17792131?u=372b27056ec82f1ae03d8b3f37ef55b04a7cfdd1&v=4 + url: https://github.com/TaigoFr +- login: davidhuser count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/112889052?v=4 - url: https://github.com/vtgn + avatarUrl: https://avatars.githubusercontent.com/u/4357648?u=6ed702f8f6d49a8b2a0ed33cbd8ab59c2d7db7f7&v=4 + url: https://github.com/davidhuser +- login: KianAnbarestani + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/145364424?u=dcc3d8fb4ca07d36fb52a17f38b6650565de40be&v=4 + url: https://github.com/KianAnbarestani +- login: Kludex + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4 + url: https://github.com/Kludex six_months_experts: -- login: luzzodev - count: 57 - avatarUrl: https://avatars.githubusercontent.com/u/27291415?u=5607ae1ce75c5f54f09500ca854227f7bfd2033b&v=4 - url: https://github.com/luzzodev - login: YuriiMotov - count: 56 + count: 749 avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=e83a39697a2d33ab2ec9bfbced794ee48bc29cec&v=4 url: https://github.com/YuriiMotov -- login: Kludex - count: 34 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4 - url: https://github.com/Kludex +- login: luzzodev + count: 51 + avatarUrl: https://avatars.githubusercontent.com/u/27291415?u=5607ae1ce75c5f54f09500ca854227f7bfd2033b&v=4 + url: https://github.com/luzzodev - login: alv2017 - count: 25 + count: 26 avatarUrl: https://avatars.githubusercontent.com/u/31544722?v=4 url: https://github.com/alv2017 +- login: Kludex + count: 20 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4 + url: https://github.com/Kludex +- login: valentinDruzhinin + count: 14 + avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4 + url: https://github.com/valentinDruzhinin - login: jgould22 - count: 17 + count: 13 avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 url: https://github.com/jgould22 -- login: sehraramiz - count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/14166324?u=8fac65e84dfff24245d304a5b5b09f7b5bd69dc9&v=4 - url: https://github.com/sehraramiz - login: JavierSanchezCastro - count: 9 + count: 10 avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4 url: https://github.com/JavierSanchezCastro +- login: sachinh35 + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/21972708?u=8560b97b8b41e175f476270b56de8a493b84f302&v=4 + url: https://github.com/sachinh35 - login: yauhen-sobaleu count: 9 avatarUrl: https://avatars.githubusercontent.com/u/51629535?u=fc1817060daf2df438bfca86c44f33da5cd667db&v=4 url: https://github.com/yauhen-sobaleu -- login: estebanx64 - count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/10840422?u=45f015f95e1c0f06df602be4ab688d4b854cc8a8&v=4 - url: https://github.com/estebanx64 -- login: yvallois - count: 7 - avatarUrl: https://avatars.githubusercontent.com/u/36999744?v=4 - url: https://github.com/yvallois - login: tiangolo - count: 6 + count: 8 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4 url: https://github.com/tiangolo -- login: yokwejuste +- login: raceychan + count: 6 + avatarUrl: https://avatars.githubusercontent.com/u/75417963?u=060c62870ec5a791765e63ac20d8885d11143786&v=4 + url: https://github.com/raceychan +- login: DoctorJohn + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/14076775?u=2913e70a6142772847e91e2aaa5b9152391715e9&v=4 + url: https://github.com/DoctorJohn +- login: sehraramiz + count: 5 + avatarUrl: https://avatars.githubusercontent.com/u/14166324?u=8fac65e84dfff24245d304a5b5b09f7b5bd69dc9&v=4 + url: https://github.com/sehraramiz +- login: eqsdxr count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/71908316?u=592c1e42aa0ee5cb94890e0b863e2acc78cc3bbc&v=4 - url: https://github.com/yokwejuste -- login: sachinh35 - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/21972708?u=8560b97b8b41e175f476270b56de8a493b84f302&v=4 - url: https://github.com/sachinh35 -- login: viniciusCalcantara - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/108818737?u=3d7ffe5808843ee4372f9cc5a559ff1674cf1792&v=4 - url: https://github.com/viniciusCalcantara + avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=58fddf77ed76966eaa8c73eea9bea4bb0c53b673&v=4 + url: https://github.com/eqsdxr - login: SobikXexe count: 3 avatarUrl: https://avatars.githubusercontent.com/u/87701130?v=4 url: https://github.com/SobikXexe -- login: chaitanyarahalkar +- login: EverStarck + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/51029456?u=343409b7cb6b3ea6a59359f4e8370d9c3f140ecd&v=4 + url: https://github.com/EverStarck +- login: henrymcl + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/26480299?v=4 + url: https://github.com/henrymcl +- login: jymchng count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/24942959?u=d3fbbc622540cb50b956585d5aec5037e01e4b1f&v=4 - url: https://github.com/chaitanyarahalkar + avatarUrl: https://avatars.githubusercontent.com/u/27895426?u=fb88c47775147d62a395fdb895d1af4148c7b566&v=4 + url: https://github.com/jymchng +- login: adsouza + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/275832?v=4 + url: https://github.com/adsouza +- login: Brikas + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/80290187?v=4 + url: https://github.com/Brikas +- login: JacobHayes + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/2555532?u=354a525847a276bbb4426b0c95791a8ba5970f9b&v=4 + url: https://github.com/JacobHayes +- login: TaigoFr + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/17792131?u=372b27056ec82f1ae03d8b3f37ef55b04a7cfdd1&v=4 + url: https://github.com/TaigoFr +- login: davidhuser + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/4357648?u=6ed702f8f6d49a8b2a0ed33cbd8ab59c2d7db7f7&v=4 + url: https://github.com/davidhuser +- login: PidgeyBE + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/19860056?u=47b584eb1c1ab45e31c1b474109a962d7e82be49&v=4 + url: https://github.com/PidgeyBE - login: KianAnbarestani count: 2 avatarUrl: https://avatars.githubusercontent.com/u/145364424?u=dcc3d8fb4ca07d36fb52a17f38b6650565de40be&v=4 url: https://github.com/KianAnbarestani +- login: Ykaiqx + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/56395004?u=1eebf5ce25a8067f7bfa6251a24f667be492d9d6&v=4 + url: https://github.com/Ykaiqx - login: sinisaos count: 2 avatarUrl: https://avatars.githubusercontent.com/u/30960668?v=4 @@ -415,30 +463,14 @@ six_months_experts: count: 2 avatarUrl: https://avatars.githubusercontent.com/u/64859146?u=d52a6ecf8d83d2927e2ae270bdfcc83495dba8c9&v=4 url: https://github.com/Ale-Cas -- login: adsouza - count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/275832?v=4 - url: https://github.com/adsouza -- login: Synrom - count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/30272537?v=4 - url: https://github.com/Synrom -- login: PREPONDERANCE - count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/112809059?u=30ab12dc9ddba2f94ab90e6ad4ad8bc5cfa7fccd&v=4 - url: https://github.com/PREPONDERANCE - login: nbx3 count: 2 avatarUrl: https://avatars.githubusercontent.com/u/34649527?u=943812f69e0d40adbd3fa1c9b8ef50dd971a2a45&v=4 url: https://github.com/nbx3 - login: marsboy02 count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/86903678?u=fa4a6b91eea3a11ae93c162616ca5edf51c68572&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/86903678?u=efe3aa9e4b22689df7633a96328fb35bf4a23905&v=4 url: https://github.com/marsboy02 -- login: EverStarck - count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/51029456?u=343409b7cb6b3ea6a59359f4e8370d9c3f140ecd&v=4 - url: https://github.com/EverStarck - login: vtgn count: 2 avatarUrl: https://avatars.githubusercontent.com/u/112889052?v=4 @@ -447,159 +479,131 @@ six_months_experts: count: 2 avatarUrl: https://avatars.githubusercontent.com/u/9466879?v=4 url: https://github.com/Trinkes -- login: XiaoXinYo - count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/56395004?u=1eebf5ce25a8067f7bfa6251a24f667be492d9d6&v=4 - url: https://github.com/XiaoXinYo -- login: iloveitaly - count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/150855?v=4 - url: https://github.com/iloveitaly -- login: LincolnPuzey - count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/18750802?v=4 - url: https://github.com/LincolnPuzey -- login: Knighthawk-Leo - count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/72437494?u=27c68db94a3107b605e603cc136f4ba83f0106d5&v=4 - url: https://github.com/Knighthawk-Leo -- login: gelezo43 - count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/40732698?u=611f39d3c1d2f4207a590937a78c1f10eed6232c&v=4 - url: https://github.com/gelezo43 -- login: AliYmn - count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/18416653?u=98c1fca46c7e4dabe8c39d17b5e55d1511d41cf9&v=4 - url: https://github.com/AliYmn -- login: RichieB2B - count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/1461970?u=edaa57d1077705244ea5c9244f4783d94ff11f12&v=4 - url: https://github.com/RichieB2B -- login: iiotsrc - count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/131771119?u=bcaf2559ef6266af70b151b7fda31a1ee3dbecb3&v=4 - url: https://github.com/iiotsrc -- login: Kfir-G - count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/57500876?u=0cd29db046a17f12f382d398141319fca7ff230a&v=4 - url: https://github.com/Kfir-G one_year_experts: - login: YuriiMotov - count: 172 + count: 831 avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=e83a39697a2d33ab2ec9bfbced794ee48bc29cec&v=4 url: https://github.com/YuriiMotov -- login: Kludex - count: 63 - avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4 - url: https://github.com/Kludex - login: luzzodev - count: 61 + count: 84 avatarUrl: https://avatars.githubusercontent.com/u/27291415?u=5607ae1ce75c5f54f09500ca854227f7bfd2033b&v=4 url: https://github.com/luzzodev +- login: Kludex + count: 55 + avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4 + url: https://github.com/Kludex - login: sinisaos count: 41 avatarUrl: https://avatars.githubusercontent.com/u/30960668?v=4 url: https://github.com/sinisaos -- login: JavierSanchezCastro - count: 33 - avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4 - url: https://github.com/JavierSanchezCastro -- login: jgould22 - count: 27 - avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 - url: https://github.com/jgould22 - login: alv2017 - count: 25 + count: 26 avatarUrl: https://avatars.githubusercontent.com/u/31544722?v=4 url: https://github.com/alv2017 +- login: JavierSanchezCastro + count: 25 + avatarUrl: https://avatars.githubusercontent.com/u/72013291?u=ae5679e6bd971d9d98cd5e76e8683f83642ba950&v=4 + url: https://github.com/JavierSanchezCastro - login: tiangolo - count: 24 + count: 22 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4 url: https://github.com/tiangolo -- login: ceb10n - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4 - url: https://github.com/ceb10n -- login: estebanx64 - count: 13 - avatarUrl: https://avatars.githubusercontent.com/u/10840422?u=45f015f95e1c0f06df602be4ab688d4b854cc8a8&v=4 - url: https://github.com/estebanx64 -- login: n8sty - count: 13 - avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 - url: https://github.com/n8sty +- login: jgould22 + count: 17 + avatarUrl: https://avatars.githubusercontent.com/u/4335847?u=ed77f67e0bb069084639b24d812dbb2a2b1dc554&v=4 + url: https://github.com/jgould22 +- login: valentinDruzhinin + count: 14 + avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4 + url: https://github.com/valentinDruzhinin - login: Kfir-G count: 13 avatarUrl: https://avatars.githubusercontent.com/u/57500876?u=0cd29db046a17f12f382d398141319fca7ff230a&v=4 url: https://github.com/Kfir-G +- login: estebanx64 + count: 11 + avatarUrl: https://avatars.githubusercontent.com/u/10840422?u=45f015f95e1c0f06df602be4ab688d4b854cc8a8&v=4 + url: https://github.com/estebanx64 - login: sehraramiz count: 11 avatarUrl: https://avatars.githubusercontent.com/u/14166324?u=8fac65e84dfff24245d304a5b5b09f7b5bd69dc9&v=4 url: https://github.com/sehraramiz -- login: PhysicallyActive - count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/160476156?u=7a8e44f4a43d3bba636f795bb7d9476c9233b4d8&v=4 - url: https://github.com/PhysicallyActive -- login: mattmess1221 - count: 11 - avatarUrl: https://avatars.githubusercontent.com/u/3409962?u=d22ea18aa8ea688af25a45df306134d593621a44&v=4 - url: https://github.com/mattmess1221 +- login: ceb10n + count: 10 + avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4 + url: https://github.com/ceb10n +- login: sachinh35 + count: 9 + avatarUrl: https://avatars.githubusercontent.com/u/21972708?u=8560b97b8b41e175f476270b56de8a493b84f302&v=4 + url: https://github.com/sachinh35 - login: yauhen-sobaleu count: 9 avatarUrl: https://avatars.githubusercontent.com/u/51629535?u=fc1817060daf2df438bfca86c44f33da5cd667db&v=4 url: https://github.com/yauhen-sobaleu -- login: AIdjis +- login: n8sty count: 8 - avatarUrl: https://avatars.githubusercontent.com/u/88404339?u=2a80d80b054e9228391e32fb9bb39571509dab6a&v=4 - url: https://github.com/AIdjis + avatarUrl: https://avatars.githubusercontent.com/u/2964996?v=4 + url: https://github.com/n8sty - login: yvallois count: 7 avatarUrl: https://avatars.githubusercontent.com/u/36999744?v=4 url: https://github.com/yvallois -- login: hasansezertasan - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/13135006?u=99f0b0f0fc47e88e8abb337b4447357939ef93e7&v=4 - url: https://github.com/hasansezertasan -- login: gustavosett +- login: raceychan + count: 6 + avatarUrl: https://avatars.githubusercontent.com/u/75417963?u=060c62870ec5a791765e63ac20d8885d11143786&v=4 + url: https://github.com/raceychan +- login: DoctorJohn count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/99373133?u=1382fe27034a0179f07cf989f63c4f23017f043c&v=4 - url: https://github.com/gustavosett -- login: chyok + avatarUrl: https://avatars.githubusercontent.com/u/14076775?u=2913e70a6142772847e91e2aaa5b9152391715e9&v=4 + url: https://github.com/DoctorJohn +- login: AIdjis count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/32629225?u=3b7c30e8a09426a1b9284f6e8a0ae53a525596bf&v=4 - url: https://github.com/chyok -- login: PREPONDERANCE - count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/112809059?u=30ab12dc9ddba2f94ab90e6ad4ad8bc5cfa7fccd&v=4 - url: https://github.com/PREPONDERANCE -- login: svlandeg + avatarUrl: https://avatars.githubusercontent.com/u/88404339?u=2a80d80b054e9228391e32fb9bb39571509dab6a&v=4 + url: https://github.com/AIdjis +- login: eqsdxr count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4 - url: https://github.com/svlandeg + avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=58fddf77ed76966eaa8c73eea9bea4bb0c53b673&v=4 + url: https://github.com/eqsdxr - login: TomFaulkner count: 4 avatarUrl: https://avatars.githubusercontent.com/u/14956620?v=4 url: https://github.com/TomFaulkner - login: yokwejuste count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/71908316?u=592c1e42aa0ee5cb94890e0b863e2acc78cc3bbc&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/71908316?u=4ba43bd63c169b5c015137d8916752a44001445a&v=4 url: https://github.com/yokwejuste -- login: binbjz +- login: PhysicallyActive count: 4 - avatarUrl: https://avatars.githubusercontent.com/u/8213913?u=40b777c625cf53dcdc6afc4aa127de67c48bf610&v=4 - url: https://github.com/binbjz -- login: dbfreem + avatarUrl: https://avatars.githubusercontent.com/u/160476156?u=7a8e44f4a43d3bba636f795bb7d9476c9233b4d8&v=4 + url: https://github.com/PhysicallyActive +- login: svlandeg + count: 4 + avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4 + url: https://github.com/svlandeg +- login: mattmess1221 count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/9778569?u=f2f1e9135b5e4f1b0c6821a548b17f97572720fc&v=4 - url: https://github.com/dbfreem -- login: sachinh35 + avatarUrl: https://avatars.githubusercontent.com/u/3409962?u=d22ea18aa8ea688af25a45df306134d593621a44&v=4 + url: https://github.com/mattmess1221 +- login: pythonweb2 count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/21972708?u=8560b97b8b41e175f476270b56de8a493b84f302&v=4 - url: https://github.com/sachinh35 + avatarUrl: https://avatars.githubusercontent.com/u/32141163?v=4 + url: https://github.com/pythonweb2 - login: viniciusCalcantara count: 3 avatarUrl: https://avatars.githubusercontent.com/u/108818737?u=3d7ffe5808843ee4372f9cc5a559ff1674cf1792&v=4 url: https://github.com/viniciusCalcantara +- login: davidhuser + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/4357648?u=6ed702f8f6d49a8b2a0ed33cbd8ab59c2d7db7f7&v=4 + url: https://github.com/davidhuser +- login: bertomaniac + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/10235051?u=14484a96833228a7b29fee4a7916d411c242c4f6&v=4 + url: https://github.com/bertomaniac +- login: dbfreem + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/9778569?u=f2f1e9135b5e4f1b0c6821a548b17f97572720fc&v=4 + url: https://github.com/dbfreem - login: SobikXexe count: 3 avatarUrl: https://avatars.githubusercontent.com/u/87701130?v=4 @@ -616,46 +620,38 @@ one_year_experts: count: 3 avatarUrl: https://avatars.githubusercontent.com/u/48672727?u=34d7b4ade252687d22a27cf53037b735b244bfc1&v=4 url: https://github.com/Isuxiz -- login: bertomaniac - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/10235051?u=14484a96833228a7b29fee4a7916d411c242c4f6&v=4 - url: https://github.com/bertomaniac -- login: deight93 - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/37678115?u=a608798b5bd0034183a9c430ebb42fb266db86ce&v=4 - url: https://github.com/deight93 - login: Minibrams count: 3 avatarUrl: https://avatars.githubusercontent.com/u/8108085?u=b028dbc308fa8485e0e2e9402b3d03d8deb22bf9&v=4 url: https://github.com/Minibrams -- login: alexandercronin - count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/8014288?u=69580504c51a0cdd756fc47b23bb7f404bd694e7&v=4 - url: https://github.com/alexandercronin - login: yanggeorge count: 2 avatarUrl: https://avatars.githubusercontent.com/u/2434407?v=4 url: https://github.com/yanggeorge -- login: chaitanyarahalkar +- login: mmzeynalli count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/24942959?u=d3fbbc622540cb50b956585d5aec5037e01e4b1f&v=4 - url: https://github.com/chaitanyarahalkar -- login: KianAnbarestani + avatarUrl: https://avatars.githubusercontent.com/u/33568903?u=19efd0c0722730b83a70b7c86c36e5b7d83e07d2&v=4 + url: https://github.com/mmzeynalli +- login: jd-solanki count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/145364424?u=dcc3d8fb4ca07d36fb52a17f38b6650565de40be&v=4 - url: https://github.com/KianAnbarestani -- login: rustonaut + avatarUrl: https://avatars.githubusercontent.com/u/47495003?u=6e225cb42c688d0cd70e65c6baedb9f5922b1178&v=4 + url: https://github.com/jd-solanki +- login: EverStarck count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/7632017?u=652bb86c1399727082c929fd4666fd7fa65923b1&v=4 - url: https://github.com/rustonaut -- login: Ale-Cas + avatarUrl: https://avatars.githubusercontent.com/u/51029456?u=343409b7cb6b3ea6a59359f4e8370d9c3f140ecd&v=4 + url: https://github.com/EverStarck +- login: slafs count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/64859146?u=d52a6ecf8d83d2927e2ae270bdfcc83495dba8c9&v=4 - url: https://github.com/Ale-Cas -- login: CharlesPerrotMinotHCHB + avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4 + url: https://github.com/slafs +- login: henrymcl count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/112571330?u=a9628848d6096b491135727435a2a253152995a1&v=4 - url: https://github.com/CharlesPerrotMinotHCHB + avatarUrl: https://avatars.githubusercontent.com/u/26480299?v=4 + url: https://github.com/henrymcl +- login: jymchng + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/27895426?u=fb88c47775147d62a395fdb895d1af4148c7b566&v=4 + url: https://github.com/jymchng - login: adsouza count: 2 avatarUrl: https://avatars.githubusercontent.com/u/275832?v=4 @@ -668,59 +664,59 @@ one_year_experts: count: 2 avatarUrl: https://avatars.githubusercontent.com/u/835733?u=8c72dec16fa560bdc81113354f2ffd79ad062bde&v=4 url: https://github.com/gaby -- login: nbx3 +- login: christiansicari count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/34649527?u=943812f69e0d40adbd3fa1c9b8ef50dd971a2a45&v=4 - url: https://github.com/nbx3 -- login: marsboy02 + avatarUrl: https://avatars.githubusercontent.com/u/29756552?v=4 + url: https://github.com/christiansicari +- login: Brikas count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/86903678?u=fa4a6b91eea3a11ae93c162616ca5edf51c68572&v=4 - url: https://github.com/marsboy02 -- login: EverStarck + avatarUrl: https://avatars.githubusercontent.com/u/80290187?v=4 + url: https://github.com/Brikas +- login: JacobHayes count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/51029456?u=343409b7cb6b3ea6a59359f4e8370d9c3f140ecd&v=4 - url: https://github.com/EverStarck -- login: Trolldemorted + avatarUrl: https://avatars.githubusercontent.com/u/2555532?u=354a525847a276bbb4426b0c95791a8ba5970f9b&v=4 + url: https://github.com/JacobHayes +- login: TaigoFr count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/10261186?v=4 - url: https://github.com/Trolldemorted -- login: anantgupta129 + avatarUrl: https://avatars.githubusercontent.com/u/17792131?u=372b27056ec82f1ae03d8b3f37ef55b04a7cfdd1&v=4 + url: https://github.com/TaigoFr +- login: rlimberger count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/66518357?u=6e25dcd84638f17d2c6df5dc26f07fd7c6dc118e&v=4 - url: https://github.com/anantgupta129 -- login: slafs + avatarUrl: https://avatars.githubusercontent.com/u/4841242?u=6a13252caf3cedceb07b6e2775b6592445d13b70&v=4 + url: https://github.com/rlimberger +- login: iloveitaly count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4 - url: https://github.com/slafs -- login: ddahan + avatarUrl: https://avatars.githubusercontent.com/u/150855?v=4 + url: https://github.com/iloveitaly +- login: iiotsrc count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/1933516?u=1d200a620e8d6841df017e9f2bb7efb58b580f40&v=4 - url: https://github.com/ddahan -- login: vtgn + avatarUrl: https://avatars.githubusercontent.com/u/131771119?u=bcaf2559ef6266af70b151b7fda31a1ee3dbecb3&v=4 + url: https://github.com/iiotsrc +- login: AmirHmZz count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/112889052?v=4 - url: https://github.com/vtgn -- login: redb0 + avatarUrl: https://avatars.githubusercontent.com/u/38752106?u=07f80e451bda00a9492bbc764e49d24ad3ada8cc&v=4 + url: https://github.com/AmirHmZz +- login: PidgeyBE count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/30475117?v=4 - url: https://github.com/redb0 -- login: pedroconceicao + avatarUrl: https://avatars.githubusercontent.com/u/19860056?u=47b584eb1c1ab45e31c1b474109a962d7e82be49&v=4 + url: https://github.com/PidgeyBE +- login: KianAnbarestani count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/32837064?u=5a0e6559bc391442629a28b6923790b54deb4464&v=4 - url: https://github.com/pedroconceicao -- login: msukmanowsky + avatarUrl: https://avatars.githubusercontent.com/u/145364424?u=dcc3d8fb4ca07d36fb52a17f38b6650565de40be&v=4 + url: https://github.com/KianAnbarestani +- login: Ykaiqx count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/362755?u=782e6bf5b9f0356c3f74b4d894fda9f179252086&v=4 - url: https://github.com/msukmanowsky -- login: rishabhc32 + avatarUrl: https://avatars.githubusercontent.com/u/56395004?u=1eebf5ce25a8067f7bfa6251a24f667be492d9d6&v=4 + url: https://github.com/Ykaiqx +- login: AliYmn count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/15983714?u=147776509107af8bdf099223e1840d3f40f944da&v=4 - url: https://github.com/rishabhc32 -- login: meower1 + avatarUrl: https://avatars.githubusercontent.com/u/18416653?u=a77e2605e3ce6aaf6fef8ad4a7b0d32954fba47a&v=4 + url: https://github.com/AliYmn +- login: dolfinus count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/109747197?u=0a5cc2a6ae74e558f0afc2874da85132e5953d8b&v=4 - url: https://github.com/meower1 -- login: Trinkes + avatarUrl: https://avatars.githubusercontent.com/u/4661021?u=ed5ddadcf36d9b943ebe61febe0b96ee34e5425d&v=4 + url: https://github.com/dolfinus +- login: gelezo43 count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/9466879?v=4 - url: https://github.com/Trinkes + avatarUrl: https://avatars.githubusercontent.com/u/40732698?u=611f39d3c1d2f4207a590937a78c1f10eed6232c&v=4 + url: https://github.com/gelezo43 diff --git a/docs/en/data/sponsors.yml b/docs/en/data/sponsors.yml index b06e51477..f712b6179 100644 --- a/docs/en/data/sponsors.yml +++ b/docs/en/data/sponsors.yml @@ -30,7 +30,7 @@ silver: - url: https://databento.com/ title: Pay as you go for market data img: https://fastapi.tiangolo.com/img/sponsors/databento.svg - - url: https://speakeasy.com?utm_source=fastapi+repo&utm_medium=github+sponsorship + - url: https://speakeasy.com/editor?utm_source=fastapi+repo&utm_medium=github+sponsorship title: SDKs for your API | Speakeasy img: https://fastapi.tiangolo.com/img/sponsors/speakeasy.png - url: https://www.svix.com/ diff --git a/docs/en/data/topic_repos.yml b/docs/en/data/topic_repos.yml index 1f6ae55bd..ab9f21995 100644 --- a/docs/en/data/topic_repos.yml +++ b/docs/en/data/topic_repos.yml @@ -1,495 +1,495 @@ - name: full-stack-fastapi-template html_url: https://github.com/fastapi/full-stack-fastapi-template - stars: 33079 + stars: 34156 owner_login: fastapi owner_html_url: https://github.com/fastapi - name: Hello-Python html_url: https://github.com/mouredev/Hello-Python - stars: 30350 + stars: 30835 owner_login: mouredev owner_html_url: https://github.com/mouredev - name: serve html_url: https://github.com/jina-ai/serve - stars: 21593 + stars: 21631 owner_login: jina-ai owner_html_url: https://github.com/jina-ai - name: HivisionIDPhotos html_url: https://github.com/Zeyi-Lin/HivisionIDPhotos - stars: 17229 + stars: 18125 owner_login: Zeyi-Lin owner_html_url: https://github.com/Zeyi-Lin - name: sqlmodel html_url: https://github.com/fastapi/sqlmodel - stars: 16068 + stars: 16249 owner_login: fastapi owner_html_url: https://github.com/fastapi - name: Douyin_TikTok_Download_API html_url: https://github.com/Evil0ctal/Douyin_TikTok_Download_API - stars: 12689 + stars: 13279 owner_login: Evil0ctal owner_html_url: https://github.com/Evil0ctal - name: fastapi-best-practices html_url: https://github.com/zhanymkanov/fastapi-best-practices - stars: 11965 + stars: 12334 owner_login: zhanymkanov owner_html_url: https://github.com/zhanymkanov - name: awesome-fastapi html_url: https://github.com/mjhea0/awesome-fastapi - stars: 9773 + stars: 9934 owner_login: mjhea0 owner_html_url: https://github.com/mjhea0 - name: FastUI html_url: https://github.com/pydantic/FastUI - stars: 8829 + stars: 8838 owner_login: pydantic owner_html_url: https://github.com/pydantic +- name: XHS-Downloader + html_url: https://github.com/JoeanAmier/XHS-Downloader + stars: 7962 + owner_login: JoeanAmier + owner_html_url: https://github.com/JoeanAmier - name: nonebot2 html_url: https://github.com/nonebot/nonebot2 - stars: 6779 + stars: 6834 owner_login: nonebot owner_html_url: https://github.com/nonebot - name: FileCodeBox html_url: https://github.com/vastsa/FileCodeBox - stars: 6652 + stars: 6783 owner_login: vastsa owner_html_url: https://github.com/vastsa -- name: serge - html_url: https://github.com/serge-chat/serge - stars: 5722 - owner_login: serge-chat - owner_html_url: https://github.com/serge-chat +- name: fastapi_mcp + html_url: https://github.com/tadata-org/fastapi_mcp + stars: 5846 + owner_login: tadata-org + owner_html_url: https://github.com/tadata-org - name: hatchet html_url: https://github.com/hatchet-dev/hatchet - stars: 5607 + stars: 5773 owner_login: hatchet-dev owner_html_url: https://github.com/hatchet-dev +- name: serge + html_url: https://github.com/serge-chat/serge + stars: 5728 + owner_login: serge-chat + owner_html_url: https://github.com/serge-chat - name: polar html_url: https://github.com/polarsource/polar - stars: 5327 + stars: 5709 owner_login: polarsource owner_html_url: https://github.com/polarsource - name: fastapi-users html_url: https://github.com/fastapi-users/fastapi-users - stars: 5235 + stars: 5336 owner_login: fastapi-users owner_html_url: https://github.com/fastapi-users -- name: fastapi_mcp - html_url: https://github.com/tadata-org/fastapi_mcp - stars: 5193 - owner_login: tadata-org - owner_html_url: https://github.com/tadata-org -- name: SurfSense - html_url: https://github.com/MODSetter/SurfSense - stars: 4833 - owner_login: MODSetter - owner_html_url: https://github.com/MODSetter -- name: chatgpt-web-share - html_url: https://github.com/chatpire/chatgpt-web-share - stars: 4307 - owner_login: chatpire - owner_html_url: https://github.com/chatpire - name: strawberry html_url: https://github.com/strawberry-graphql/strawberry - stars: 4281 + stars: 4317 owner_login: strawberry-graphql owner_html_url: https://github.com/strawberry-graphql +- name: chatgpt-web-share + html_url: https://github.com/chatpire/chatgpt-web-share + stars: 4301 + owner_login: chatpire + owner_html_url: https://github.com/chatpire - name: atrilabs-engine html_url: https://github.com/Atri-Labs/atrilabs-engine - stars: 4110 + stars: 4106 owner_login: Atri-Labs owner_html_url: https://github.com/Atri-Labs - name: dynaconf html_url: https://github.com/dynaconf/dynaconf - stars: 4008 + stars: 4045 owner_login: dynaconf owner_html_url: https://github.com/dynaconf - name: poem html_url: https://github.com/poem-web/poem - stars: 3977 + stars: 4037 owner_login: poem-web owner_html_url: https://github.com/poem-web - name: farfalle html_url: https://github.com/rashadphz/farfalle - stars: 3317 + stars: 3348 owner_login: rashadphz owner_html_url: https://github.com/rashadphz +- name: LitServe + html_url: https://github.com/Lightning-AI/LitServe + stars: 3347 + owner_login: Lightning-AI + owner_html_url: https://github.com/Lightning-AI - name: fastapi-admin html_url: https://github.com/fastapi-admin/fastapi-admin - stars: 3253 + stars: 3309 owner_login: fastapi-admin owner_html_url: https://github.com/fastapi-admin - name: datamodel-code-generator html_url: https://github.com/koxudaxi/datamodel-code-generator - stars: 3228 + stars: 3291 owner_login: koxudaxi owner_html_url: https://github.com/koxudaxi -- name: LitServe - html_url: https://github.com/Lightning-AI/LitServe - stars: 3175 - owner_login: Lightning-AI - owner_html_url: https://github.com/Lightning-AI - name: logfire html_url: https://github.com/pydantic/logfire - stars: 3172 + stars: 3288 owner_login: pydantic owner_html_url: https://github.com/pydantic -- name: opyrator - html_url: https://github.com/ml-tooling/opyrator - stars: 3122 - owner_login: ml-tooling - owner_html_url: https://github.com/ml-tooling - name: huma html_url: https://github.com/danielgtaylor/huma - stars: 3110 + stars: 3201 owner_login: danielgtaylor owner_html_url: https://github.com/danielgtaylor +- name: opyrator + html_url: https://github.com/ml-tooling/opyrator + stars: 3132 + owner_login: ml-tooling + owner_html_url: https://github.com/ml-tooling +- name: Kokoro-FastAPI + html_url: https://github.com/remsky/Kokoro-FastAPI + stars: 3099 + owner_login: remsky + owner_html_url: https://github.com/remsky - name: docarray html_url: https://github.com/docarray/docarray - stars: 3068 + stars: 3075 owner_login: docarray owner_html_url: https://github.com/docarray - name: fastapi-realworld-example-app html_url: https://github.com/nsidnev/fastapi-realworld-example-app - stars: 2892 + stars: 2902 owner_login: nsidnev owner_html_url: https://github.com/nsidnev -- name: Kokoro-FastAPI - html_url: https://github.com/remsky/Kokoro-FastAPI - stars: 2883 - owner_login: remsky - owner_html_url: https://github.com/remsky -- name: uvicorn-gunicorn-fastapi-docker - html_url: https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker - stars: 2770 - owner_login: tiangolo - owner_html_url: https://github.com/tiangolo - name: tracecat html_url: https://github.com/TracecatHQ/tracecat - stars: 2740 + stars: 2888 owner_login: TracecatHQ owner_html_url: https://github.com/TracecatHQ +- name: uvicorn-gunicorn-fastapi-docker + html_url: https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker + stars: 2775 + owner_login: tiangolo + owner_html_url: https://github.com/tiangolo - name: best-of-web-python html_url: https://github.com/ml-tooling/best-of-web-python - stars: 2517 + stars: 2537 owner_login: ml-tooling owner_html_url: https://github.com/ml-tooling - name: RasaGPT html_url: https://github.com/paulpierre/RasaGPT - stars: 2423 + stars: 2427 owner_login: paulpierre owner_html_url: https://github.com/paulpierre - name: fastapi-react html_url: https://github.com/Buuntu/fastapi-react - stars: 2376 + stars: 2397 owner_login: Buuntu owner_html_url: https://github.com/Buuntu - name: FastAPI-template html_url: https://github.com/s3rius/FastAPI-template - stars: 2301 + stars: 2334 owner_login: s3rius owner_html_url: https://github.com/s3rius - name: nextpy html_url: https://github.com/dot-agent/nextpy - stars: 2289 + stars: 2295 owner_login: dot-agent owner_html_url: https://github.com/dot-agent - name: sqladmin html_url: https://github.com/aminalaee/sqladmin - stars: 2196 + stars: 2235 owner_login: aminalaee owner_html_url: https://github.com/aminalaee - name: 30-Days-of-Python html_url: https://github.com/codingforentrepreneurs/30-Days-of-Python - stars: 2179 + stars: 2181 owner_login: codingforentrepreneurs owner_html_url: https://github.com/codingforentrepreneurs - name: langserve html_url: https://github.com/langchain-ai/langserve - stars: 2098 + stars: 2119 owner_login: langchain-ai owner_html_url: https://github.com/langchain-ai - name: fastapi-utils html_url: https://github.com/fastapiutils/fastapi-utils - stars: 2077 + stars: 2100 owner_login: fastapiutils owner_html_url: https://github.com/fastapiutils - name: supabase-py html_url: https://github.com/supabase/supabase-py - stars: 2047 + stars: 2084 owner_login: supabase owner_html_url: https://github.com/supabase - name: solara html_url: https://github.com/widgetti/solara - stars: 2044 + stars: 2056 owner_login: widgetti owner_html_url: https://github.com/widgetti - name: mangum html_url: https://github.com/Kludex/mangum - stars: 1905 + stars: 1923 owner_login: Kludex owner_html_url: https://github.com/Kludex - name: python-week-2022 html_url: https://github.com/rochacbruno/python-week-2022 - stars: 1823 + stars: 1821 owner_login: rochacbruno owner_html_url: https://github.com/rochacbruno -- name: manage-fastapi - html_url: https://github.com/ycd/manage-fastapi - stars: 1754 - owner_login: ycd - owner_html_url: https://github.com/ycd - name: agentkit html_url: https://github.com/BCG-X-Official/agentkit - stars: 1746 + stars: 1765 owner_login: BCG-X-Official owner_html_url: https://github.com/BCG-X-Official +- name: manage-fastapi + html_url: https://github.com/ycd/manage-fastapi + stars: 1756 + owner_login: ycd + owner_html_url: https://github.com/ycd - name: ormar html_url: https://github.com/collerek/ormar - stars: 1742 + stars: 1755 owner_login: collerek owner_html_url: https://github.com/collerek - name: langchain-serve html_url: https://github.com/jina-ai/langchain-serve - stars: 1630 + stars: 1631 owner_login: jina-ai owner_html_url: https://github.com/jina-ai -- name: termpair - html_url: https://github.com/cs01/termpair - stars: 1611 - owner_login: cs01 - owner_html_url: https://github.com/cs01 - name: piccolo html_url: https://github.com/piccolo-orm/piccolo - stars: 1609 + stars: 1629 owner_login: piccolo-orm owner_html_url: https://github.com/piccolo-orm -- name: coronavirus-tracker-api - html_url: https://github.com/ExpDev07/coronavirus-tracker-api - stars: 1587 - owner_login: ExpDev07 - owner_html_url: https://github.com/ExpDev07 -- name: fastapi-cache - html_url: https://github.com/long2ice/fastapi-cache - stars: 1575 - owner_login: long2ice - owner_html_url: https://github.com/long2ice +- name: termpair + html_url: https://github.com/cs01/termpair + stars: 1616 + owner_login: cs01 + owner_html_url: https://github.com/cs01 - name: openapi-python-client html_url: https://github.com/openapi-generators/openapi-python-client - stars: 1568 + stars: 1603 owner_login: openapi-generators owner_html_url: https://github.com/openapi-generators -- name: fastapi-crudrouter - html_url: https://github.com/awtkns/fastapi-crudrouter - stars: 1508 - owner_login: awtkns - owner_html_url: https://github.com/awtkns +- name: fastapi-cache + html_url: https://github.com/long2ice/fastapi-cache + stars: 1589 + owner_login: long2ice + owner_html_url: https://github.com/long2ice +- name: coronavirus-tracker-api + html_url: https://github.com/ExpDev07/coronavirus-tracker-api + stars: 1580 + owner_login: ExpDev07 + owner_html_url: https://github.com/ExpDev07 - name: slowapi html_url: https://github.com/laurentS/slowapi - stars: 1501 + stars: 1533 owner_login: laurentS owner_html_url: https://github.com/laurentS +- name: fastapi-crudrouter + html_url: https://github.com/awtkns/fastapi-crudrouter + stars: 1518 + owner_login: awtkns + owner_html_url: https://github.com/awtkns - name: awesome-fastapi-projects html_url: https://github.com/Kludex/awesome-fastapi-projects - stars: 1453 + stars: 1461 owner_login: Kludex owner_html_url: https://github.com/Kludex +- name: vue-fastapi-admin + html_url: https://github.com/mizhexiaoxiao/vue-fastapi-admin + stars: 1409 + owner_login: mizhexiaoxiao + owner_html_url: https://github.com/mizhexiaoxiao - name: awesome-python-resources html_url: https://github.com/DjangoEx/awesome-python-resources - stars: 1390 + stars: 1393 owner_login: DjangoEx owner_html_url: https://github.com/DjangoEx - name: fastapi-pagination html_url: https://github.com/uriyyo/fastapi-pagination - stars: 1353 + stars: 1378 owner_login: uriyyo owner_html_url: https://github.com/uriyyo -- name: budgetml - html_url: https://github.com/ebhy/budgetml - stars: 1342 - owner_login: ebhy - owner_html_url: https://github.com/ebhy - name: fastapi-boilerplate html_url: https://github.com/teamhide/fastapi-boilerplate - stars: 1325 + stars: 1348 owner_login: teamhide owner_html_url: https://github.com/teamhide -- name: vue-fastapi-admin - html_url: https://github.com/mizhexiaoxiao/vue-fastapi-admin - stars: 1306 - owner_login: mizhexiaoxiao - owner_html_url: https://github.com/mizhexiaoxiao +- name: budgetml + html_url: https://github.com/ebhy/budgetml + stars: 1344 + owner_login: ebhy + owner_html_url: https://github.com/ebhy - name: fastapi-amis-admin html_url: https://github.com/amisadmin/fastapi-amis-admin - stars: 1256 + stars: 1284 owner_login: amisadmin owner_html_url: https://github.com/amisadmin +- name: bracket + html_url: https://github.com/evroon/bracket + stars: 1274 + owner_login: evroon + owner_html_url: https://github.com/evroon - name: fastapi-tutorial html_url: https://github.com/liaogx/fastapi-tutorial - stars: 1245 + stars: 1265 owner_login: liaogx owner_html_url: https://github.com/liaogx - name: fastapi-code-generator html_url: https://github.com/koxudaxi/fastapi-code-generator - stars: 1201 + stars: 1216 owner_login: koxudaxi owner_html_url: https://github.com/koxudaxi -- name: bracket - html_url: https://github.com/evroon/bracket - stars: 1201 - owner_login: evroon - owner_html_url: https://github.com/evroon - name: bolt-python html_url: https://github.com/slackapi/bolt-python - stars: 1179 + stars: 1190 owner_login: slackapi owner_html_url: https://github.com/slackapi -- name: fastapi_production_template - html_url: https://github.com/zhanymkanov/fastapi_production_template - stars: 1147 - owner_login: zhanymkanov - owner_html_url: https://github.com/zhanymkanov +- name: fastcrud + html_url: https://github.com/benavlabs/fastcrud + stars: 1169 + owner_login: benavlabs + owner_html_url: https://github.com/benavlabs - name: prometheus-fastapi-instrumentator html_url: https://github.com/trallnag/prometheus-fastapi-instrumentator - stars: 1145 + stars: 1167 owner_login: trallnag owner_html_url: https://github.com/trallnag +- name: fastapi_production_template + html_url: https://github.com/zhanymkanov/fastapi_production_template + stars: 1165 + owner_login: zhanymkanov + owner_html_url: https://github.com/zhanymkanov - name: bedrock-chat html_url: https://github.com/aws-samples/bedrock-chat - stars: 1143 + stars: 1163 owner_login: aws-samples owner_html_url: https://github.com/aws-samples - name: langchain-extract html_url: https://github.com/langchain-ai/langchain-extract - stars: 1134 + stars: 1142 owner_login: langchain-ai owner_html_url: https://github.com/langchain-ai - name: odmantic html_url: https://github.com/art049/odmantic - stars: 1118 + stars: 1121 owner_login: art049 owner_html_url: https://github.com/art049 +- name: fastapi_best_architecture + html_url: https://github.com/fastapi-practices/fastapi_best_architecture + stars: 1118 + owner_login: fastapi-practices + owner_html_url: https://github.com/fastapi-practices - name: fastapi-alembic-sqlmodel-async html_url: https://github.com/jonra1993/fastapi-alembic-sqlmodel-async - stars: 1110 + stars: 1116 owner_login: jonra1993 owner_html_url: https://github.com/jonra1993 -- name: fastcrud - html_url: https://github.com/benavlabs/fastcrud - stars: 1080 +- name: FastAPI-boilerplate + html_url: https://github.com/benavlabs/FastAPI-boilerplate + stars: 1070 owner_login: benavlabs owner_html_url: https://github.com/benavlabs - name: restish html_url: https://github.com/rest-sh/restish - stars: 1056 + stars: 1069 owner_login: rest-sh owner_html_url: https://github.com/rest-sh -- name: fastapi_best_architecture - html_url: https://github.com/fastapi-practices/fastapi_best_architecture - stars: 1050 - owner_login: fastapi-practices - owner_html_url: https://github.com/fastapi-practices - name: runhouse html_url: https://github.com/run-house/runhouse - stars: 1034 + stars: 1037 owner_login: run-house owner_html_url: https://github.com/run-house - name: autollm html_url: https://github.com/viddexa/autollm - stars: 992 + stars: 994 owner_login: viddexa owner_html_url: https://github.com/viddexa - name: lanarky html_url: https://github.com/ajndkr/lanarky - stars: 990 + stars: 992 owner_login: ajndkr owner_html_url: https://github.com/ajndkr -- name: FastAPI-boilerplate - html_url: https://github.com/benavlabs/FastAPI-boilerplate - stars: 985 - owner_login: benavlabs - owner_html_url: https://github.com/benavlabs - name: authx html_url: https://github.com/yezz123/authx - stars: 938 + stars: 953 owner_login: yezz123 owner_html_url: https://github.com/yezz123 - name: secure html_url: https://github.com/TypeError/secure - stars: 935 + stars: 941 owner_login: TypeError owner_html_url: https://github.com/TypeError -- name: langcorn - html_url: https://github.com/msoedov/langcorn - stars: 925 - owner_login: msoedov - owner_html_url: https://github.com/msoedov - name: energy-forecasting html_url: https://github.com/iusztinpaul/energy-forecasting - stars: 913 + stars: 928 owner_login: iusztinpaul owner_html_url: https://github.com/iusztinpaul +- name: langcorn + html_url: https://github.com/msoedov/langcorn + stars: 927 + owner_login: msoedov + owner_html_url: https://github.com/msoedov - name: titiler html_url: https://github.com/developmentseed/titiler - stars: 886 + stars: 901 owner_login: developmentseed owner_html_url: https://github.com/developmentseed - name: flock html_url: https://github.com/Onelevenvy/flock - stars: 866 + stars: 896 owner_login: Onelevenvy owner_html_url: https://github.com/Onelevenvy -- name: httpdbg - html_url: https://github.com/cle-b/httpdbg - stars: 863 - owner_login: cle-b - owner_html_url: https://github.com/cle-b +- name: fastapi-langgraph-agent-production-ready-template + html_url: https://github.com/wassim249/fastapi-langgraph-agent-production-ready-template + stars: 896 + owner_login: wassim249 + owner_html_url: https://github.com/wassim249 - name: marker-api html_url: https://github.com/adithya-s-k/marker-api - stars: 859 + stars: 875 owner_login: adithya-s-k owner_html_url: https://github.com/adithya-s-k -- name: ludic - html_url: https://github.com/getludic/ludic - stars: 845 - owner_login: getludic - owner_html_url: https://github.com/getludic +- name: httpdbg + html_url: https://github.com/cle-b/httpdbg + stars: 870 + owner_login: cle-b + owner_html_url: https://github.com/cle-b - name: fastapi-do-zero html_url: https://github.com/dunossauro/fastapi-do-zero - stars: 827 + stars: 855 owner_login: dunossauro owner_html_url: https://github.com/dunossauro +- name: ludic + html_url: https://github.com/getludic/ludic + stars: 849 + owner_login: getludic + owner_html_url: https://github.com/getludic - name: fastapi-observability html_url: https://github.com/blueswen/fastapi-observability - stars: 823 + stars: 837 owner_login: blueswen owner_html_url: https://github.com/blueswen -- name: fastapi-langgraph-agent-production-ready-template - html_url: https://github.com/wassim249/fastapi-langgraph-agent-production-ready-template - stars: 803 - owner_login: wassim249 - owner_html_url: https://github.com/wassim249 -- name: fastapi-mail - html_url: https://github.com/sabuhish/fastapi-mail - stars: 798 - owner_login: sabuhish - owner_html_url: https://github.com/sabuhish +- name: fastapi-scaf + html_url: https://github.com/atpuxiner/fastapi-scaf + stars: 821 + owner_login: atpuxiner + owner_html_url: https://github.com/atpuxiner - name: starlette-admin html_url: https://github.com/jowilf/starlette-admin - stars: 785 + stars: 808 owner_login: jowilf owner_html_url: https://github.com/jowilf -- name: lccn_predictor - html_url: https://github.com/baoliay2008/lccn_predictor - stars: 767 - owner_login: baoliay2008 - owner_html_url: https://github.com/baoliay2008 +- name: fastapi-mail + html_url: https://github.com/sabuhish/fastapi-mail + stars: 807 + owner_login: sabuhish + owner_html_url: https://github.com/sabuhish - name: aktools html_url: https://github.com/akfamily/aktools - stars: 759 + stars: 796 owner_login: akfamily owner_html_url: https://github.com/akfamily -- name: KonomiTV - html_url: https://github.com/tsukumijima/KonomiTV - stars: 748 - owner_login: tsukumijima - owner_html_url: https://github.com/tsukumijima +- name: RuoYi-Vue3-FastAPI + html_url: https://github.com/insistence/RuoYi-Vue3-FastAPI + stars: 782 + owner_login: insistence + owner_html_url: https://github.com/insistence diff --git a/docs/en/data/translation_reviewers.yml b/docs/en/data/translation_reviewers.yml index aad3e4fac..4f3c95b27 100644 --- a/docs/en/data/translation_reviewers.yml +++ b/docs/en/data/translation_reviewers.yml @@ -10,7 +10,7 @@ Xewus: url: https://github.com/Xewus sodaMelon: login: sodaMelon - count: 125 + count: 126 avatarUrl: https://avatars.githubusercontent.com/u/66295123?u=be939db90f1119efee9e6110cc05066ff1f40f00&v=4 url: https://github.com/sodaMelon ceb10n: @@ -30,7 +30,7 @@ hasansezertasan: url: https://github.com/hasansezertasan hard-coders: login: hard-coders - count: 92 + count: 93 avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4 url: https://github.com/hard-coders alv2017: @@ -70,7 +70,7 @@ mattwang44: url: https://github.com/mattwang44 tiangolo: login: tiangolo - count: 52 + count: 53 avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4 url: https://github.com/tiangolo Laineyzhang55: @@ -148,6 +148,11 @@ nilslindemann: count: 35 avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4 url: https://github.com/nilslindemann +mezgoodle: + login: mezgoodle + count: 35 + avatarUrl: https://avatars.githubusercontent.com/u/41520940?u=4a9c765af688389d54296845d18b8f6cd6ddf09a&v=4 + url: https://github.com/mezgoodle rjNemo: login: rjNemo count: 34 @@ -158,11 +163,6 @@ codingjenny: count: 34 avatarUrl: https://avatars.githubusercontent.com/u/103817302?u=3a042740dc0ff58615da0d8679230966fd7693e8&v=4 url: https://github.com/codingjenny -mezgoodle: - login: mezgoodle - count: 33 - avatarUrl: https://avatars.githubusercontent.com/u/41520940?u=4a9c765af688389d54296845d18b8f6cd6ddf09a&v=4 - url: https://github.com/mezgoodle akarev0: login: akarev0 count: 33 @@ -243,6 +243,11 @@ mycaule: count: 25 avatarUrl: https://avatars.githubusercontent.com/u/6161385?u=e3cec75bd6d938a0d73fae0dc5534d1ab2ed1b0e&v=4 url: https://github.com/mycaule +YuriiMotov: + login: YuriiMotov + count: 24 + avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=e83a39697a2d33ab2ec9bfbced794ee48bc29cec&v=4 + url: https://github.com/YuriiMotov Aruelius: login: Aruelius count: 24 @@ -268,6 +273,11 @@ axel584: count: 23 avatarUrl: https://avatars.githubusercontent.com/u/1334088?u=9667041f5b15dc002b6f9665fda8c0412933ac04&v=4 url: https://github.com/axel584 +DianaTrufanova: + login: DianaTrufanova + count: 23 + avatarUrl: https://avatars.githubusercontent.com/u/119067607?u=1cd55f841b68b4a187fa6d06a7dafa5f070195aa&v=4 + url: https://github.com/DianaTrufanova AGolicyn: login: AGolicyn count: 21 @@ -328,6 +338,11 @@ Limsunoh: count: 18 avatarUrl: https://avatars.githubusercontent.com/u/90311848?u=f456e0c5709fd50c8cd2898b551558eda14e5f21&v=4 url: https://github.com/Limsunoh +SofiiaTrufanova: + login: SofiiaTrufanova + count: 18 + avatarUrl: https://avatars.githubusercontent.com/u/63260929?u=483e0b64fabc76343b3be39b7e1dcb930a95e1bb&v=4 + url: https://github.com/SofiiaTrufanova bezaca: login: bezaca count: 17 @@ -373,11 +388,6 @@ JaeHyuckSa: count: 16 avatarUrl: https://avatars.githubusercontent.com/u/104830931?u=6e352201714a05154e5d0ccf91b4715a951c622e&v=4 url: https://github.com/JaeHyuckSa -SofiiaTrufanova: - login: SofiiaTrufanova - count: 16 - avatarUrl: https://avatars.githubusercontent.com/u/63260929?u=483e0b64fabc76343b3be39b7e1dcb930a95e1bb&v=4 - url: https://github.com/SofiiaTrufanova Jedore: login: Jedore count: 15 @@ -388,11 +398,6 @@ kim-sangah: count: 15 avatarUrl: https://avatars.githubusercontent.com/u/173775778?v=4 url: https://github.com/kim-sangah -DianaTrufanova: - login: DianaTrufanova - count: 15 - avatarUrl: https://avatars.githubusercontent.com/u/119067607?u=1cd55f841b68b4a187fa6d06a7dafa5f070195aa&v=4 - url: https://github.com/DianaTrufanova PandaHun: login: PandaHun count: 14 @@ -533,6 +538,11 @@ Lufa1u: count: 11 avatarUrl: https://avatars.githubusercontent.com/u/112495876?u=087658920ed9e74311597bdd921d8d2de939d276&v=4 url: https://github.com/Lufa1u +waketzheng: + login: waketzheng + count: 11 + avatarUrl: https://avatars.githubusercontent.com/u/35413830?u=df19e4fd5bb928e7d086e053ef26a46aad23bf84&v=4 + url: https://github.com/waketzheng KNChiu: login: KNChiu count: 11 @@ -593,16 +603,21 @@ nick-cjyx9: count: 10 avatarUrl: https://avatars.githubusercontent.com/u/119087246?u=c35aab03f082430be8a1edd80f5625b44819a0d8&v=4 url: https://github.com/nick-cjyx9 -waketzheng: - login: waketzheng - count: 10 - avatarUrl: https://avatars.githubusercontent.com/u/35413830?u=df19e4fd5bb928e7d086e053ef26a46aad23bf84&v=4 - url: https://github.com/waketzheng lucasbalieiro: login: lucasbalieiro count: 10 avatarUrl: https://avatars.githubusercontent.com/u/37416577?u=eabaf4aebbaa88a94a4886273edba689012cee70&v=4 url: https://github.com/lucasbalieiro +maru0123-2004: + login: maru0123-2004 + count: 10 + avatarUrl: https://avatars.githubusercontent.com/u/43961566?u=16ed8603a4d6a4665cb6c53a7aece6f31379b769&v=4 + url: https://github.com/maru0123-2004 +Zhongheng-Cheng: + login: Zhongheng-Cheng + count: 10 + avatarUrl: https://avatars.githubusercontent.com/u/95612344?u=a0f7730a3cc7486827965e01a119ad610bda4b0a&v=4 + url: https://github.com/Zhongheng-Cheng RunningIkkyu: login: RunningIkkyu count: 9 @@ -646,7 +661,7 @@ riroan: MinLee0210: login: MinLee0210 count: 9 - avatarUrl: https://avatars.githubusercontent.com/u/57653278?u=3c4b6e9d69bff148d09fe022ddf867e564acaa44&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/57653278?u=8ca05a7efbc76048183da00da87d148b755a3ba8&v=4 url: https://github.com/MinLee0210 yodai-yodai: login: yodai-yodai @@ -663,11 +678,6 @@ JoaoGustavoRogel: count: 9 avatarUrl: https://avatars.githubusercontent.com/u/29525510?u=a0a91251f5e43e132608d55d28ccb8645c5ea405&v=4 url: https://github.com/JoaoGustavoRogel -Zhongheng-Cheng: - login: Zhongheng-Cheng - count: 9 - avatarUrl: https://avatars.githubusercontent.com/u/95612344?u=a0f7730a3cc7486827965e01a119ad610bda4b0a&v=4 - url: https://github.com/Zhongheng-Cheng Yarous: login: Yarous count: 9 @@ -713,11 +723,6 @@ camigomezdev: count: 8 avatarUrl: https://avatars.githubusercontent.com/u/16061815?u=25b5ebc042fff53fa03dc107ded10e36b1b7a5b9&v=4 url: https://github.com/camigomezdev -maru0123-2004: - login: maru0123-2004 - count: 8 - avatarUrl: https://avatars.githubusercontent.com/u/43961566?u=16ed8603a4d6a4665cb6c53a7aece6f31379b769&v=4 - url: https://github.com/maru0123-2004 minaton-ru: login: minaton-ru count: 8 @@ -748,6 +753,11 @@ anthonycepeda: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/72019805?u=60bdf46240cff8fca482ff0fc07d963fd5e1a27c&v=4 url: https://github.com/anthonycepeda +Muaytie666: + login: Muaytie666 + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/198508825?v=4 + url: https://github.com/Muaytie666 fabioueno: login: fabioueno count: 7 @@ -773,6 +783,11 @@ d2a-raudenaerde: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/5213150?v=4 url: https://github.com/d2a-raudenaerde +valentinDruzhinin: + login: valentinDruzhinin + count: 7 + avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4 + url: https://github.com/valentinDruzhinin Zerohertz: login: Zerohertz count: 7 @@ -781,7 +796,7 @@ Zerohertz: deniscapeto: login: deniscapeto count: 6 - avatarUrl: https://avatars.githubusercontent.com/u/12864353?u=dbc20c5c1171feab5df4db46488b675d53cb5b07&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/12864353?u=20c5b2300b264a585a8381acf3cef44bcfcc1ead&v=4 url: https://github.com/deniscapeto bsab: login: bsab @@ -878,11 +893,11 @@ bankofsardine: count: 6 avatarUrl: https://avatars.githubusercontent.com/u/44944207?u=0368e1b698ffab6bf29e202f9fd2dddd352429f1&v=4 url: https://github.com/bankofsardine -valentinDruzhinin: - login: valentinDruzhinin +Rekl0w: + login: Rekl0w count: 6 - avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4 - url: https://github.com/valentinDruzhinin + avatarUrl: https://avatars.githubusercontent.com/u/91488737?u=3b62b04a3e6699eab9b1eea4e88c09a39b753a17&v=4 + url: https://github.com/Rekl0w rsip22: login: rsip22 count: 5 @@ -966,7 +981,7 @@ ChuyuChoyeon: frwl404: login: frwl404 count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/42642656?u=572a5a33762e07eaa6ebd58d9d773abdb1de41c3&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/42642656?u=8395a3d991d9fac86901277d76f0f70857b56ec5&v=4 url: https://github.com/frwl404 esrefzeki: login: esrefzeki @@ -1328,6 +1343,11 @@ Sion99: count: 3 avatarUrl: https://avatars.githubusercontent.com/u/82511301?v=4 url: https://github.com/Sion99 +nymous: + login: nymous + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/4216559?u=360a36fb602cded27273cbfc0afc296eece90662&v=4 + url: https://github.com/nymous EpsilonRationes: login: EpsilonRationes count: 3 @@ -1366,7 +1386,7 @@ GDemay: maxscheijen: login: maxscheijen count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/47034840?u=eb98f37882528ea349ca4e5255fa64ac3fef0294&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/47034840?v=4 url: https://github.com/maxscheijen celestywang: login: celestywang @@ -1566,7 +1586,7 @@ raphaelauv: Fahad-Md-Kamal: login: Fahad-Md-Kamal count: 2 - avatarUrl: https://avatars.githubusercontent.com/u/34704464?u=f96c6cbd25b06274e3ff96bc961ca91b3f876481&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/34704464?u=141086368c5557d5a1a533fe291f21f9fc584458&v=4 url: https://github.com/Fahad-Md-Kamal zxcq544: login: zxcq544 @@ -1753,6 +1773,11 @@ kiharito: count: 2 avatarUrl: https://avatars.githubusercontent.com/u/38311245?v=4 url: https://github.com/kiharito +t4f1d: + login: t4f1d + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/4054172?u=463d5ce0ec8ad8582f6e9351bb8c9a5105b39bb7&v=4 + url: https://github.com/t4f1d J-Fuji: login: J-Fuji count: 2 @@ -1783,3 +1808,13 @@ Azazul123: count: 2 avatarUrl: https://avatars.githubusercontent.com/u/102759111?u=b48ce6e30a81a23467cc30e0c011bcc57f0326ab&v=4 url: https://github.com/Azazul123 +ykertytsky: + login: ykertytsky + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/83857001?u=1172902656ee604cf37f5e36abe938cd34a97a32&v=4 + url: https://github.com/ykertytsky +NavesSapnis: + login: NavesSapnis + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/79222417?u=b5b10291b8e9130ca84fd20f0a641e04ed94b6b1&v=4 + url: https://github.com/NavesSapnis diff --git a/docs/en/data/translators.yml b/docs/en/data/translators.yml index 51d05003b..3cd6120d0 100644 --- a/docs/en/data/translators.yml +++ b/docs/en/data/translators.yml @@ -8,16 +8,16 @@ jaystone776: count: 46 avatarUrl: https://avatars.githubusercontent.com/u/11191137?u=299205a95e9b6817a43144a48b643346a5aac5cc&v=4 url: https://github.com/jaystone776 +valentinDruzhinin: + login: valentinDruzhinin + count: 29 + avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4 + url: https://github.com/valentinDruzhinin ceb10n: login: ceb10n count: 27 avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4 url: https://github.com/ceb10n -valentinDruzhinin: - login: valentinDruzhinin - count: 24 - avatarUrl: https://avatars.githubusercontent.com/u/12831905?u=aae1ebc675c91e8fa582df4fcc4fc4128106344d&v=4 - url: https://github.com/valentinDruzhinin tokusumi: login: tokusumi count: 23 @@ -108,6 +108,11 @@ ptt3199: count: 7 avatarUrl: https://avatars.githubusercontent.com/u/51350651?u=2c3d947a80283e32bf616d4c3af139a6be69680f&v=4 url: https://github.com/ptt3199 +NinaHwang: + login: NinaHwang + count: 6 + avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=241f2cb6d38a2d379536608a8ea5a22ed4b1a3ea&v=4 + url: https://github.com/NinaHwang batlopes: login: batlopes count: 6 @@ -138,11 +143,6 @@ Attsun1031: count: 5 avatarUrl: https://avatars.githubusercontent.com/u/1175560?v=4 url: https://github.com/Attsun1031 -NinaHwang: - login: NinaHwang - count: 5 - avatarUrl: https://avatars.githubusercontent.com/u/79563565?u=241f2cb6d38a2d379536608a8ea5a22ed4b1a3ea&v=4 - url: https://github.com/NinaHwang tiangolo: login: tiangolo count: 5 @@ -296,7 +296,7 @@ pe-brian: maxscheijen: login: maxscheijen count: 3 - avatarUrl: https://avatars.githubusercontent.com/u/47034840?u=eb98f37882528ea349ca4e5255fa64ac3fef0294&v=4 + avatarUrl: https://avatars.githubusercontent.com/u/47034840?v=4 url: https://github.com/maxscheijen ilacftemp: login: ilacftemp @@ -343,6 +343,11 @@ Rishat-F: count: 3 avatarUrl: https://avatars.githubusercontent.com/u/66554797?v=4 url: https://github.com/Rishat-F +ruzia: + login: ruzia + count: 3 + avatarUrl: https://avatars.githubusercontent.com/u/24503?v=4 + url: https://github.com/ruzia izaguerreiro: login: izaguerreiro count: 2 @@ -523,3 +528,8 @@ EgorOnishchuk: count: 2 avatarUrl: https://avatars.githubusercontent.com/u/120256301?v=4 url: https://github.com/EgorOnishchuk +NavesSapnis: + login: NavesSapnis + count: 2 + avatarUrl: https://avatars.githubusercontent.com/u/79222417?u=b5b10291b8e9130ca84fd20f0a641e04ed94b6b1&v=4 + url: https://github.com/NavesSapnis diff --git a/docs/en/docs/advanced/generate-clients.md b/docs/en/docs/advanced/generate-clients.md index b2aef5037..55e6a08b1 100644 --- a/docs/en/docs/advanced/generate-clients.md +++ b/docs/en/docs/advanced/generate-clients.md @@ -22,7 +22,7 @@ And it shows their true commitment to FastAPI and its **community** (you), as th For example, you might want to try: -* Speakeasy +* Speakeasy * Stainless * liblab diff --git a/docs/en/docs/advanced/response-directly.md b/docs/en/docs/advanced/response-directly.md index 691b1e7cd..759b762b5 100644 --- a/docs/en/docs/advanced/response-directly.md +++ b/docs/en/docs/advanced/response-directly.md @@ -58,7 +58,7 @@ You could put your XML content in a string, put that in a `Response`, and return ## Notes -When you return a `Response` directly its data is not validated, converted (serialized), nor documented automatically. +When you return a `Response` directly its data is not validated, converted (serialized), or documented automatically. But you can still document it as described in [Additional Responses in OpenAPI](additional-responses.md){.internal-link target=_blank}. diff --git a/docs/en/docs/async.md b/docs/en/docs/async.md index 63bd8ca68..8207ec480 100644 --- a/docs/en/docs/async.md +++ b/docs/en/docs/async.md @@ -40,7 +40,7 @@ def results(): --- -If your application (somehow) doesn't have to communicate with anything else and wait for it to respond, use `async def`. +If your application (somehow) doesn't have to communicate with anything else and wait for it to respond, use `async def`, even if you don't need to use `await` inside. --- diff --git a/docs/en/docs/contributing.md b/docs/en/docs/contributing.md index 1b70a0ea9..91c39c927 100644 --- a/docs/en/docs/contributing.md +++ b/docs/en/docs/contributing.md @@ -181,6 +181,28 @@ as Uvicorn by default will use the port `8000`, the documentation on port `8008` ### Translations +/// warning | Attention + +**Update on Translations** + +We're updating the way we handle documentation translations. + +Until now, we invited community members to translate pages via pull requests, which were then reviewed by at least two native speakers. While this has helped bring FastAPI to many more users, we’ve also run into several challenges - some languages have only a few translated pages, others are outdated and hard to maintain over time. +To improve this, we’re working on automation tools 🤖 to manage translations more efficiently. Once ready, documentation will be machine-translated and still reviewed by at least two native speakers ✅ before publishing. This will allow us to keep translations up-to-date while reducing the review burden on maintainers. + +What’s changing now: + +* 🚫 We’re no longer accepting new community-submitted translation PRs. + +* ⏳ Existing open PRs will be reviewed and can still be merged if completed within the next 3 weeks (since July 11 2025). + +* 🌐 In the future, we will only support languages where at least three active native speakers are available to review and maintain translations. + +This transition will help us keep translations more consistent and timely while better supporting our contributors 🙌. Thank you to everyone who has contributed so far — your help has been invaluable! 💖 + +/// + + Help with translations is VERY MUCH appreciated! And it can't be done without the help from the community. 🌎 🚀 Here are the steps to help with translations. diff --git a/docs/en/docs/index.md b/docs/en/docs/index.md index 0f3623ed5..938882d7d 100644 --- a/docs/en/docs/index.md +++ b/docs/en/docs/index.md @@ -468,15 +468,20 @@ Used by Starlette: * jinja2 - Required if you want to use the default template configuration. * python-multipart - Required if you want to support form "parsing", with `request.form()`. -Used by FastAPI / Starlette: +Used by FastAPI: * uvicorn - for the server that loads and serves your application. This includes `uvicorn[standard]`, which includes some dependencies (e.g. `uvloop`) needed for high performance serving. -* `fastapi-cli` - to provide the `fastapi` command. +* `fastapi-cli[standard]` - to provide the `fastapi` command. + * This includes `fastapi-cloud-cli`, which allows you to deploy your FastAPI application to FastAPI Cloud. ### Without `standard` Dependencies If you don't want to include the `standard` optional dependencies, you can install with `pip install fastapi` instead of `pip install "fastapi[standard]"`. +### Without `fastapi-cloud-cli` + +If you want to install FastAPI with the standard dependencies but without the `fastapi-cloud-cli`, you can install with `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. + ### Additional Optional Dependencies There are some additional dependencies you might want to install. diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 46dbf7536..83c06c013 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,12 +7,108 @@ hide: ## Latest Changes +### Translations + +* 🌐 Add Persian translation for `docs/fa/docs/python-types.md`. PR [#13524](https://github.com/fastapi/fastapi/pull/13524) by [@Mohammad222PR](https://github.com/Mohammad222PR). +* 🌐 Update Portuguese Translation for `docs/pt/docs/project-generation.md`. PR [#13875](https://github.com/fastapi/fastapi/pull/13875) by [@EdmilsonRodrigues](https://github.com/EdmilsonRodrigues). +* 🌐 Add Persian translation for `docs/fa/docs/async.md`. PR [#13541](https://github.com/fastapi/fastapi/pull/13541) by [@Mohammad222PR](https://github.com/Mohammad222PR). +* 🌐 Add Bangali translation for `docs/bn/about/index.md`. PR [#13882](https://github.com/fastapi/fastapi/pull/13882) by [@sajjadrahman56](https://github.com/sajjadrahman56). + +### Internal + +* 👥 Update FastAPI People - Experts. PR [#13889](https://github.com/fastapi/fastapi/pull/13889) by [@tiangolo](https://github.com/tiangolo). +* 🔨 Update FastAPI People sleep interval, use external settings. PR [#13888](https://github.com/fastapi/fastapi/pull/13888) by [@tiangolo](https://github.com/tiangolo). + +## 0.116.1 + +### Upgrades + +* ⬆️ Upgrade Starlette supported version range to `>=0.40.0,<0.48.0`. PR [#13884](https://github.com/fastapi/fastapi/pull/13884) by [@tiangolo](https://github.com/tiangolo). + +### Docs + +* 📝 Add notification about impending changes in Translations to `docs/en/docs/contributing.md`. PR [#13886](https://github.com/fastapi/fastapi/pull/13886) by [@YuriiMotov](https://github.com/YuriiMotov). + +### Internal + +* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#13871](https://github.com/fastapi/fastapi/pull/13871) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). + +## 0.116.0 + +### Features + +* ✨ Add support for deploying to FastAPI Cloud with `fastapi deploy`. PR [#13870](https://github.com/fastapi/fastapi/pull/13870) by [@tiangolo](https://github.com/tiangolo). + +Installing `fastapi[standard]` now includes `fastapi-cloud-cli`. + +This will allow you to deploy to [FastAPI Cloud](https://fastapicloud.com) with the `fastapi deploy` command. + +If you want to install `fastapi` with the standard dependencies but without `fastapi-cloud-cli`, you can install instead `fastapi[standard-no-fastapi-cloud-cli]`. + +### Translations + +* 🌐 Add Russian translation for `docs/ru/docs/advanced/response-directly.md`. PR [#13801](https://github.com/fastapi/fastapi/pull/13801) by [@NavesSapnis](https://github.com/NavesSapnis). +* 🌐 Add Russian translation for `docs/ru/docs/advanced/additional-status-codes.md`. PR [#13799](https://github.com/fastapi/fastapi/pull/13799) by [@NavesSapnis](https://github.com/NavesSapnis). +* 🌐 Add Ukrainian translation for `docs/uk/docs/tutorial/body-updates.md`. PR [#13804](https://github.com/fastapi/fastapi/pull/13804) by [@valentinDruzhinin](https://github.com/valentinDruzhinin). + +### Internal + +* ⬆ Bump pillow from 11.1.0 to 11.3.0. PR [#13852](https://github.com/fastapi/fastapi/pull/13852) by [@dependabot[bot]](https://github.com/apps/dependabot). +* 👥 Update FastAPI People - Sponsors. PR [#13846](https://github.com/fastapi/fastapi/pull/13846) by [@tiangolo](https://github.com/tiangolo). +* 👥 Update FastAPI GitHub topic repositories. PR [#13848](https://github.com/fastapi/fastapi/pull/13848) by [@tiangolo](https://github.com/tiangolo). +* ⬆ Bump mkdocs-material from 9.6.1 to 9.6.15. PR [#13849](https://github.com/fastapi/fastapi/pull/13849) by [@dependabot[bot]](https://github.com/apps/dependabot). +* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#13843](https://github.com/fastapi/fastapi/pull/13843) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). +* 👥 Update FastAPI People - Contributors and Translators. PR [#13845](https://github.com/fastapi/fastapi/pull/13845) by [@tiangolo](https://github.com/tiangolo). + +## 0.115.14 + +### Fixes + +* 🐛 Fix support for unions when using `Form`. PR [#13827](https://github.com/fastapi/fastapi/pull/13827) by [@patrick91](https://github.com/patrick91). + +### Docs + +* ✏️ Fix grammar mistake in `docs/en/docs/advanced/response-directly.md`. PR [#13800](https://github.com/fastapi/fastapi/pull/13800) by [@NavesSapnis](https://github.com/NavesSapnis). +* 📝 Update Speakeasy URL to Speakeasy Sandbox. PR [#13697](https://github.com/fastapi/fastapi/pull/13697) by [@ndimares](https://github.com/ndimares). + +### Translations + +* 🌐 Add Ukrainian translation for `docs/uk/docs/tutorial/response-model.md`. PR [#13792](https://github.com/fastapi/fastapi/pull/13792) by [@valentinDruzhinin](https://github.com/valentinDruzhinin). +* 🌐 Add Ukrainian translation for `docs/uk/docs/tutorial/security/index.md`. PR [#13805](https://github.com/fastapi/fastapi/pull/13805) by [@valentinDruzhinin](https://github.com/valentinDruzhinin). +* ✏️ Fix typo in `docs/ja/docs/tutorial/encoder.md`. PR [#13815](https://github.com/fastapi/fastapi/pull/13815) by [@ruzia](https://github.com/ruzia). +* ✏️ Fix typo in `docs/ja/docs/tutorial/handling-errors.md`. PR [#13814](https://github.com/fastapi/fastapi/pull/13814) by [@ruzia](https://github.com/ruzia). +* ✏️ Fix typo in `docs/ja/docs/tutorial/body-fields.md`. PR [#13802](https://github.com/fastapi/fastapi/pull/13802) by [@ruzia](https://github.com/ruzia). +* 🌐 Add Russian translation for `docs/ru/docs/advanced/index.md`. PR [#13797](https://github.com/fastapi/fastapi/pull/13797) by [@NavesSapnis](https://github.com/NavesSapnis). + +### Internal + +* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#13823](https://github.com/fastapi/fastapi/pull/13823) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). + +## 0.115.13 + +### Fixes + +* 🐛 Fix truncating the model's description with form feed (`\f`) character for Pydantic V2. PR [#13698](https://github.com/fastapi/fastapi/pull/13698) by [@YuriiMotov](https://github.com/YuriiMotov). + +### Refactors + +* ✨ Add `refreshUrl` parameter in `OAuth2PasswordBearer`. PR [#11460](https://github.com/fastapi/fastapi/pull/11460) by [@snosratiershad](https://github.com/snosratiershad). +* 🚸 Set format to password for fields `password` and `client_secret` in `OAuth2PasswordRequestForm`, make docs show password fields for passwords. PR [#11032](https://github.com/fastapi/fastapi/pull/11032) by [@Thodoris1999](https://github.com/Thodoris1999). +* ✅ Simplify tests for `settings`. PR [#13505](https://github.com/fastapi/fastapi/pull/13505) by [@valentinDruzhinin](https://github.com/valentinDruzhinin). +* ✅ Simplify tests for `validate_response_recursive`. PR [#13507](https://github.com/fastapi/fastapi/pull/13507) by [@valentinDruzhinin](https://github.com/valentinDruzhinin). + ### Upgrades * ⬆️ Update ReDoc to version 2.x. PR [#9700](https://github.com/fastapi/fastapi/pull/9700) by [@joakimnordling](https://github.com/joakimnordling). ### Docs +* 📝 Add annotations to HTTP middleware example. PR [#11530](https://github.com/fastapi/fastapi/pull/11530) by [@Kilo59](https://github.com/Kilo59). +* 📝 Clarify in CORS docs that wildcards and credentials are mutually exclusive. PR [#9829](https://github.com/fastapi/fastapi/pull/9829) by [@dfioravanti](https://github.com/dfioravanti). +* ✏️ Fix typo in docstring. PR [#13532](https://github.com/fastapi/fastapi/pull/13532) by [@comp64](https://github.com/comp64). +* 📝 Clarify guidance on using `async def` without `await`. PR [#13642](https://github.com/fastapi/fastapi/pull/13642) by [@swastikpradhan1999](https://github.com/swastikpradhan1999). +* 📝 Update exclude-parameters-from-openapi documentation links. PR [#13600](https://github.com/fastapi/fastapi/pull/13600) by [@timonrieger](https://github.com/timonrieger). +* 📝 Clarify the middleware execution order in docs. PR [#13699](https://github.com/fastapi/fastapi/pull/13699) by [@YuriiMotov](https://github.com/YuriiMotov). * 🍱 Update Drawio diagrams SVGs, single file per diagram, sans-serif font. PR [#13706](https://github.com/fastapi/fastapi/pull/13706) by [@tiangolo](https://github.com/tiangolo). * 📝 Update docs for "Help FastAPI", simplify and reduce "sponsor" section. PR [#13670](https://github.com/fastapi/fastapi/pull/13670) by [@tiangolo](https://github.com/tiangolo). * 📝 Remove unnecessary bullet from docs. PR [#13641](https://github.com/fastapi/fastapi/pull/13641) by [@Adamowoc](https://github.com/Adamowoc). @@ -24,6 +120,8 @@ hide: ### Translations +* 🌐 Add Russian Translation for `docs/ru/docs/advanced/response-change-status-code.md`. PR [#13791](https://github.com/fastapi/fastapi/pull/13791) by [@NavesSapnis](https://github.com/NavesSapnis). +* 🌐 Add Persian translation for `docs/fa/docs/learn/index.md`. PR [#13518](https://github.com/fastapi/fastapi/pull/13518) by [@Mohammad222PR](https://github.com/Mohammad222PR). * 🌐 Add Korean translation for `docs/ko/docs/advanced/sub-applications.md`. PR [#4543](https://github.com/fastapi/fastapi/pull/4543) by [@NinaHwang](https://github.com/NinaHwang). * 🌐 Add Ukrainian translation for `docs/uk/docs/tutorial/schema-extra-example.md`. PR [#13769](https://github.com/fastapi/fastapi/pull/13769) by [@valentinDruzhinin](https://github.com/valentinDruzhinin). * ✏️ Remove redundant words in docs/zh/docs/python-types.md. PR [#13774](https://github.com/fastapi/fastapi/pull/13774) by [@CharleeWa](https://github.com/CharleeWa). @@ -49,6 +147,7 @@ hide: ### Internal +* 🔨 Resolve Pydantic deprecation warnings in internal script. PR [#13696](https://github.com/fastapi/fastapi/pull/13696) by [@emmanuel-ferdman](https://github.com/emmanuel-ferdman). * 🔧 Update sponsors: remove Porter. PR [#13783](https://github.com/fastapi/fastapi/pull/13783) by [@tiangolo](https://github.com/tiangolo). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#13781](https://github.com/fastapi/fastapi/pull/13781) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#13757](https://github.com/fastapi/fastapi/pull/13757) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). diff --git a/docs/en/docs/tutorial/cors.md b/docs/en/docs/tutorial/cors.md index cf31cfcf5..5ca4437b3 100644 --- a/docs/en/docs/tutorial/cors.md +++ b/docs/en/docs/tutorial/cors.md @@ -57,7 +57,10 @@ The following arguments are supported: * `allow_origin_regex` - A regex string to match against origins that should be permitted to make cross-origin requests. e.g. `'https://.*\.example\.org'`. * `allow_methods` - A list of HTTP methods that should be allowed for cross-origin requests. Defaults to `['GET']`. You can use `['*']` to allow all standard methods. * `allow_headers` - A list of HTTP request headers that should be supported for cross-origin requests. Defaults to `[]`. You can use `['*']` to allow all headers. The `Accept`, `Accept-Language`, `Content-Language` and `Content-Type` headers are always allowed for simple CORS requests. -* `allow_credentials` - Indicate that cookies should be supported for cross-origin requests. Defaults to `False`. Also, `allow_origins` cannot be set to `['*']` for credentials to be allowed, origins must be specified. +* `allow_credentials` - Indicate that cookies should be supported for cross-origin requests. Defaults to `False`. + + None of `allow_origins`, `allow_methods` and `allow_headers` can be set to `['*']` if `allow_credentials` is set to `True`. All of them must be explicitly specified. + * `expose_headers` - Indicate any response headers that should be made accessible to the browser. Defaults to `[]`. * `max_age` - Sets a maximum time in seconds for browsers to cache CORS responses. Defaults to `600`. diff --git a/docs/en/docs/tutorial/index.md b/docs/en/docs/tutorial/index.md index 4fe38256c..17f6fb685 100644 --- a/docs/en/docs/tutorial/index.md +++ b/docs/en/docs/tutorial/index.md @@ -76,10 +76,12 @@ $ pip install "fastapi[standard]" /// note -When you install with `pip install "fastapi[standard]"` it comes with some default optional standard dependencies. +When you install with `pip install "fastapi[standard]"` it comes with some default optional standard dependencies, including `fastapi-cloud-cli`, which allows you to deploy to FastAPI Cloud. If you don't want to have those optional dependencies, you can instead install `pip install fastapi`. +If you want to install the standard dependencies but without the `fastapi-cloud-cli`, you can install with `pip install "fastapi[standard-no-fastapi-cloud-cli]"`. + /// ## Advanced User Guide diff --git a/docs/en/docs/tutorial/middleware.md b/docs/en/docs/tutorial/middleware.md index 4f7980165..b7c03a319 100644 --- a/docs/en/docs/tutorial/middleware.md +++ b/docs/en/docs/tutorial/middleware.md @@ -65,6 +65,29 @@ Here we use Speakeasy +* Speakeasy * Stainless * liblab diff --git a/docs/fa/docs/async.md b/docs/fa/docs/async.md new file mode 100644 index 000000000..e07374862 --- /dev/null +++ b/docs/fa/docs/async.md @@ -0,0 +1,444 @@ +# هم‌زمانی و async / await + +جزئیات در مورد سینتکس `async def` برای *توابع عملیات مسیر* و یه کم پیش‌زمینه در مورد کد ناهم‌زمان، هم‌زمانی و موازی‌سازی. + +## عجله داری؟ + +TL;DR: + +اگه از کتابخونه‌های سوم‌شخصی استفاده می‌کنی که بهت می‌گن با `await` صداشون کنی، مثل: + +```Python +results = await some_library() +``` + +اون وقت، *توابع عملیات مسیرت* رو با `async def` تعریف کن، اینجوری: + +```Python hl_lines="2" +@app.get('/') +async def read_results(): + results = await some_library() + return results +``` + +/// note + +فقط توی توابعی که با `async def` ساخته شدن می‌تونی از `await` استفاده کنی. + +/// + +--- + +اگه از یه کتابخونه سوم‌شخص استفاده می‌کنی که با یه چیزی (مثل دیتابیس، API، سیستم فایل و غیره) ارتباط داره و از `await` پشتیبانی نمی‌کنه (که الان برای بیشتر کتابخونه‌های دیتابیس اینجوریه)، اون وقت *توابع عملیات مسیرت* رو عادی، فقط با `def` تعریف کن، اینجوری: + +```Python hl_lines="2" +@app.get('/') +def results(): + results = some_library() + return results +``` + +--- + +اگه برنامه‌ات (به هر دلیلی) لازم نیست با چیز دیگه‌ای ارتباط برقرار کنه و منتظر جوابش بمونه، از `async def` استفاده کن. + +--- + +اگه نمی‌دونی چیکار کنی، از `def` معمولی استفاده کن. + +--- + +**توجه**: می‌تونی توی *توابع عملیات مسیرت* هر چقدر که لازم داری `def` و `async def` رو قاطی کنی و هر کدوم رو با بهترین گزینه برات تعریف کنی. FastAPI خودش کار درست رو باهاشون انجام می‌ده. + +به هر حال، توی هر کدوم از موقعیت‌های بالا، FastAPI هنوز ناهم‌زمان کار می‌کنه و خیلی خیلی سریع هست. + +ولی با دنبال کردن مراحل بالا، می‌تونه یه سری بهینه‌سازی عملکرد هم بکنه. + +## جزئیات فنی + +نسخه‌های مدرن پایتون از **"کد ناهم‌زمان"** با چیزی که بهش **"کروتین"** می‌گن پشتیبانی می‌کنن، با سینتکس **`async` و `await`**. + +بیاید این جمله رو تکه‌تکه توی بخش‌های زیر ببینیم: + +* **کد ناهم‌زمان** +* **`async` و `await`** +* **کروتین‌ها** + +## کد ناهم‌زمان + +کد ناهم‌زمان یعنی زبون 💬 یه راهی داره که به کامپیوتر / برنامه 🤖 بگه توی یه جای کد، باید منتظر بمونه تا *یه چیز دیگه* یه جای دیگه تموم بشه. فرض کن اون *یه چیز دیگه* اسمش "فایل-آروم" 📝 باشه. + +پس، توی اون مدت، کامپیوتر می‌تونه بره یه کار دیگه بکنه، تا وقتی "فایل-آروم" 📝 تموم بشه. + +بعدش کامپیوتر / برنامه 🤖 هر وقت فرصتی داشته باشه برمی‌گرده، چون دوباره منتظره، یا هر وقت همه کاری که اون لحظه داشته تموم کرده. و می‌بینه آیا کارایی که منتظرشون بوده تموم شدن یا نه، و هر کاری که باید بکنه رو انجام می‌ده. + +بعد، اون 🤖 اولین کاری که تموم شده (مثلاً "فایل-آروم" 📝 ما) رو برمی‌داره و هر کاری که باید باهاش بکنه رو ادامه می‌ده. + +این "منتظر یه چیز دیگه بودن" معمولاً به عملیات I/O اشاره داره که نسبتاً "آروم" هستن (نسبت به سرعت پردازنده و حافظه RAM)، مثل منتظر موندن برای: + +* داده‌هایی که از کلاینت از طریق شبکه فرستاده می‌شن +* داده‌هایی که برنامه‌ات فرستاده تا از طریق شبکه به کلاینت برسه +* محتوای یه فایل توی دیسک که سیستم بخوندش و به برنامه‌ات بده +* محتوایی که برنامه‌ات به سیستم داده تا توی دیسک بنویسه +* یه عملیات API از راه دور +* یه عملیات دیتابیس که تموم بشه +* یه کوئری دیتابیس که نتایجش برگرده +* و غیره. + +چون زمان اجرا بیشتر صرف انتظار برای عملیات I/O می‌شه، بهشون می‌گن عملیات "I/O bound". + +بهش "ناهم‌زمان" می‌گن چون کامپیوتر / برنامه لازم نیست با کار آروم "هم‌زمان" باشه، منتظر لحظه دقیق تموم شدن کار بمونه، در حالی که هیچ کاری نمی‌کنه، تا نتیجه رو بگیره و کارش رو ادامه بده. + +به جاش، چون یه سیستم "ناهم‌زمان" هست، وقتی کار تموم شد، می‌تونه یه کم توی صف منتظر بمونه (چند میکروثانیه) تا کامپیوتر / برنامه هر کاری که رفته بکنه رو تموم کنه، و بعد برگرده نتیجه رو بگیره و باهاش کار کنه. + +برای "هم‌زمان" (برخلاف "ناهم‌زمان") معمولاً از اصطلاح "ترتیبی" هم استفاده می‌کنن، چون کامپیوتر / برنامه همه مراحل رو به ترتیب دنبال می‌کنه قبل از اینکه بره سراغ یه کار دیگه، حتی اگه اون مراحل شامل انتظار باشن. + +### هم‌زمانی و برگرها + +این ایده **ناهم‌زمان** که بالا توضیح دادم گاهی بهش **"هم‌زمانی"** هم می‌گن. با **"موازی‌سازی"** فرق داره. + +**هم‌زمانی** و **موازی‌سازی** هر دو به "اتفاق افتادن چیزای مختلف کم‌وبیش همزمان" ربط دارن. + +ولی جزئیات بین *هم‌زمانی* و *موازی‌سازی* خیلی متفاوته. + +برای دیدن فرقش، این داستان در مورد برگرها رو تصور کن: + +### برگرهای هم‌زمان + +با عشقت می‌ری فست‌فود بگیرین، توی صف وایمیستی در حالی که صندوقدار سفارش آدمای جلوی تو رو می‌گیره. 😍 + + + +بعد نوبت تو می‌شه، سفارش دو تا برگر خیلی شیک برای خودت و عشقت می‌دی. 🍔🍔 + + + +صندوقدار یه چیزی به آشپز توی آشپزخونه می‌گه تا بدونن باید برگرهای تو رو آماده کنن (گرچه الان دارن برگرهای مشتریای قبلی رو درست می‌کنن). + + + +پول رو می‌دی. 💸 + +صندوقدار شماره نوبتت رو بهت می‌ده. + + + +وقتی منتظری، با عشقت می‌ری یه میز انتخاب می‌کنی، می‌شینی و کلی با عشقت حرف می‌زنی (چون برگرهات خیلی شیکن و آماده کردنشون یه کم طول می‌کشه). + +وقتی پشت میز با عشقت نشستی، در حالی که منتظر برگرهایی، می‌تونی اون زمان رو صرف تحسین این کنی که عشقت چقدر باحال، ناز و باهوشه ✨😍✨. + + + +وقتی منتظری و با عشقت حرف می‌زنی، هر از گاهی شماره‌ای که رو پیشخون نشون داده می‌شه رو چک می‌کنی که ببینی نوبتت شده یا نه. + +بعد یه جایی بالاخره نوبتت می‌شه. می‌ری پیشخون، برگرهات رو می‌گیری و برمی‌گردی سر میز. + + + +تو و عشقت برگرها رو می‌خورین و یه وقت خوب باهم دارین. ✨ + + + +/// info + +تصاویر قشنگ از کترینا تامپسون. 🎨 + +/// + +--- + +تصور کن تو توی این داستان کامپیوتر / برنامه 🤖 هستی. + +وقتی توی صف هستی، فقط بیکاری 😴، منتظر نوبتت هستی، کار خیلی "مفیدی" نمی‌کنی. ولی صف سریع پیش می‌ره چون صندوقدار فقط سفارش می‌گیره (آمادشون نمی‌کنه)، پس این خوبه. + +بعد، وقتی نوبتت می‌شه، کار "مفید" واقعی می‌کنی، منو رو پردازش می‌کنی، تصمیم می‌گیری چی می‌خوای، انتخاب عشقت رو می‌گیری، پول می‌دی، چک می‌کنی اسکناس یا کارت درست رو دادی، چک می‌کنی درست حساب شده، چک می‌کنی سفارش آیتمای درست رو داره و غیره. + +ولی بعد، گرچه هنوز برگرهات رو نداری، کارت با صندوقدار "موقتاً متوقف" ⏸ می‌شه، چون باید منتظر بمونی 🕙 تا برگرهات آماده بشن. + +ولی وقتی از پیشخون دور می‌شی و با شماره نوبتت سر میز می‌شینی، می‌تونی توجهت رو 🔀 به عشقت بدی و "کار" ⏯ 🤓 رو اون بکنی. بعدش دوباره داری یه چیز خیلی "مفید" انجام می‌دی، مثل لاس زدن با عشقت 😍. + +بعد صندوقدار 💁 با گذاشتن شماره‌ات رو نمایشگر پیشخون می‌گه "من با درست کردن برگرها تموم کردم"، ولی تو مثل دیوونه‌ها وقتی شماره‌ات رو نمایشگر میاد فوری نمی‌پری. می‌دونی کسی برگرهات رو نمی‌دزده چون شماره نوبتت رو داری، و اونا هم مال خودشون رو دارن. + +پس منتظر می‌مونی تا عشقت داستانش رو تموم کنه (کار فعلی ⏯ / وظیفه‌ای که داره پردازش می‌شه 🤓)، آروم لبخند می‌زنی و می‌گی که می‌ری برگرها رو بیاری ⏸. + +بعد می‌ری پیشخون 🔀، به کار اولیه که حالا تموم شده ⏯، برگرها رو می‌گیری، تشکر می‌کنی و می‌برشون سر میز. این مرحله / وظیفه تعامل با پیشخون رو تموم می‌کنه ⏹. این به نوبه خودش یه وظیفه جدید، "خوردن برگرها" 🔀 ⏯، می‌سازه، ولی اون قبلی که "گرفتن برگرها" بود تموم شده ⏹. + +### برگرهای موازی + +حالا فرض کن اینا "برگرهای هم‌زمان" نیستن، بلکه "برگرهای موازی" هستن. + +با عشقت می‌ری فست‌فود موازی بگیری. + +توی صف وایمیستی در حالی که چند تا (مثلاً 8 تا) صندوقدار که همزمان آشپز هم هستن سفارش آدمای جلوی تو رو می‌گیرن. + +همه قبل تو منتظرن برگرهاشون آماده بشه قبل از اینکه پیشخون رو ترک کنن، چون هر کدوم از 8 تا صندوقدار می‌ره و برگر رو همون موقع درست می‌کنه قبل از اینکه سفارش بعدی رو بگیره. + + + +بالاخره نوبت تو می‌شه، سفارش دو تا برگر خیلی شیک برای خودت و عشقت می‌دی. + +پول رو می‌دی 💸. + + + +صندوقدار می‌ره آشپزخونه. + +منتظر می‌مونی، جلوی پیشخون وایستادی 🕙، که کسی قبل از تو برگرهات رو نگیره، چون شماره نوبت نیست. + + + +چون تو و عشقت مشغول این هستین که نذارین کسی جلوتون بیاد و هر وقت برگرها رسیدن اونا رو بگیره، نمی‌تونی به عشقت توجه کنی. 😞 + +این کار "هم‌زمان" هست، تو با صندوقدار/آشپز 👨‍🍳 "هم‌زمان" هستی. باید منتظر بمونی 🕙 و درست همون لحظه که صندوقدار/آشپز 👨‍🍳 برگرها رو تموم می‌کنه و بهت می‌ده اونجا باشی، وگرنه ممکنه یکی دیگه اونا رو بگیره. + + + +بعد صندوقدار/آشپزت 👨‍🍳 بالاخره بعد از یه مدت طولانی انتظار 🕙 جلوی پیشخون با برگرهات برمی‌گرده. + + + +برگرهات رو می‌گیری و با عشقت می‌ری سر میز. + +فقط می‌خورینشون، و تمومه. ⏹ + + + +حرف زدن یا لاس زدن زیاد نبود چون بیشتر وقت صرف انتظار 🕙 جلوی پیشخون شد. 😞 + +/// info + +تصاویر قشنگ از کترینا تامپسون. 🎨 + +/// + +--- + +توی این سناریوی برگرهای موازی، تو یه کامپیوتر / برنامه 🤖 با دو تا پردازنده (تو و عشقت) هستی، هر دو منتظر 🕙 و توجهشون ⏯ رو برای مدت طولانی "انتظار جلوی پیشخون" 🕙 گذاشتن. + +فست‌فود 8 تا پردازنده (صندوقدار/آشپز) داره. در حالی که فست‌فود برگرهای هم‌زمان شاید فقط 2 تا داشته (یه صندوقدار و یه آشپز). + +ولی با این حال، تجربه نهایی بهترین نیست. 😞 + +--- + +این معادل موازی داستان برگرها بود. 🍔 + +برای یه مثال "واقعی‌تر" از زندگی، یه بانک رو تصور کن. + +تا همین چند وقت پیش، بیشتر بانک‌ها چند تا صندوقدار 👨‍💼👨‍💼👨‍💼👨‍💼 داشتن و یه صف بزرگ 🕙🕙🕙🕙🕙🕙🕙🕙. + +همه صندوقدارها کار رو با یه مشتری بعد از اون یکی 👨‍💼⏯ انجام می‌دادن. + +و باید توی صف 🕙 مدت زیادی منتظر بمونی وگرنه نوبتت رو از دست می‌دی. + +احتمالاً نمی‌خوای عشقت 😍 رو با خودت ببری بانک 🏦 برای کارای روزمره. + +### نتیجه‌گیری برگرها + +توی این سناریوی "برگرهای فست‌فود با عشقت"، چون کلی انتظار 🕙 هست، خیلی منطقی‌تره که یه سیستم هم‌زمان ⏸🔀⏯ داشته باشی. + +این برای بیشتر برنامه‌های وب هم صدق می‌کنه. + +خیلی خیلی کاربر، ولی سرورت منتظر 🕙 اتصال نه‌چندان خوبشون هست تا درخواست‌هاشون رو بفرستن. + +و بعد دوباره منتظر 🕙 که جواب‌ها برگردن. + +این "انتظار" 🕙 توی میکروثانیه‌ها اندازه‌گیری می‌شه، ولی با این حال، جمعش که بکنی آخرش کلی انتظار می‌شه. + +برای همین استفاده از کد ناهم‌زمان ⏸🔀⏯ برای APIهای وب خیلی منطقیه. + +این نوع ناهم‌زمانی چیزیه که NodeJS رو محبوب کرد (گرچه NodeJS موازی نیست) و نقطه قوت Go به‌عنوان یه زبون برنامه‌نویسیه. + +و همون سطح عملکردی هست که با **FastAPI** می‌گیری. + +و چون می‌تونی هم‌زمانی و موازی‌سازی رو همزمان داشته باشی، عملکرد بالاتری از بیشتر فریم‌ورک‌های تست‌شده NodeJS می‌گیری و هم‌تراز با Go، که یه زبون کامپایل‌شده نزدیک به C هست (همه اینا به لطف Starlette). + +### آیا هم‌زمانی از موازی‌سازی بهتره؟ + +نه! این نتیجه داستان نیست. + +هم‌زمانی با موازی‌سازی فرق داره. و توی **سناریوهای خاص** که کلی انتظار دارن بهتره. به همین خاطر، معمولاً برای توسعه برنامه‌های وب خیلی از موازی‌سازی بهتره. ولی نه برای همه‌چیز. + +برای اینکه یه تعادل بذاریم، این داستان کوتاه رو تصور کن: + +> باید یه خونه بزرگ و کثیف رو تمیز کنی. + +*آره، کل داستان همینه*. + +--- + +هیچ انتظاری 🕙 اونجا نیست، فقط کلی کار برای انجام دادن توی جاهای مختلف خونه. + +می‌تونی مثل مثال برگرها نوبت بذاری، اول پذیرایی، بعد آشپزخونه، ولی چون منتظر چیزی نیستی 🕙، فقط داری تمیز می‌کنی و تمیز می‌کنی، نوبت‌ها هیچ تأثیری نداره. + +با نوبت یا بدون نوبت (هم‌زمانی) همون قدر طول می‌کشه تا تمومش کنی و همون مقدار کار رو کردی. + +ولی توی این موقعیت، اگه بتونی اون 8 تا صندوقدار/آشپز/حالا-تمیزکار رو بیاری، و هر کدومشون (به‌علاوه خودت) یه قسمت از خونه رو تمیز کنن، می‌تونی همه کار رو **موازی** انجام بدی، با کمک اضافی، و خیلی زودتر تمومش کنی. + +توی این سناریو، هر کدوم از تمیزکارها (از جمله خودت) یه پردازنده‌ست که کار خودش رو می‌کنه. + +و چون بیشتر زمان اجرا صرف کار واقعی می‌شه (به جای انتظار)، و کار توی کامپیوتر با CPU انجام می‌شه، به این مشکلات می‌گن "CPU bound". + +--- + +مثال‌های رایج عملیات CPU bound چیزایی هستن که نیاز به پردازش ریاضی پیچیده دارن. + +مثلاً: + +* پردازش **صدا** یا **تصویر**. +* **بینایی کامپیوتری**: یه تصویر از میلیون‌ها پیکسل تشکیل شده، هر پیکسل 3 تا مقدار / رنگ داره، پردازشش معمولاً نیاز داره چیزی رو رو اون پیکسل‌ها همزمان حساب کنی. +* **یادگیری ماشین**: معمولاً کلی ضرب "ماتریس" و "بردار" لازم داره. یه جدول بزرگ پر از عدد رو تصور کن که همه‌شون رو همزمان ضرب می‌کنی. +* **یادگیری عمیق**: این یه زیرشاخه از یادگیری ماشینه، پس همون قضیه صدق می‌کنه. فقط این که یه جدول عدد برای ضرب کردن نیست، بلکه یه مجموعه بزرگ از اونا هست، و توی خیلی موارد از یه پردازنده خاص برای ساخت و / یا استفاده از این مدل‌ها استفاده می‌کنی. + +### هم‌زمانی + موازی‌سازی: وب + یادگیری ماشین + +با **FastAPI** می‌تونی از هم‌زمانی که برای توسعه وب خیلی رایجه (همون جذابیت اصلی NodeJS) استفاده کنی. + +ولی می‌تونی از فواید موازی‌سازی و چندپردازشی (اجرای چند پروسه به‌صورت موازی) برای کارای **CPU bound** مثل سیستم‌های یادگیری ماشین هم بهره ببری. + +این، به‌علاوه این واقعیت ساده که پایتون زبون اصلی برای **علم داده**، یادگیری ماشین و به‌خصوص یادگیری عمیقه، باعث می‌شه FastAPI یه انتخاب خیلی خوب برای APIها و برنامه‌های وب علم داده / یادگیری ماشین باشه (بین خیلی چیزای دیگه). + +برای دیدن اینکه چطور توی محیط واقعی به این موازی‌سازی برسی، بخش [استقرار](deployment/index.md){.internal-link target=_blank} رو ببین. + +## `async` و `await` + +نسخه‌های مدرن پایتون یه راه خیلی ساده و قابل‌فهم برای تعریف کد ناهم‌زمان دارن. این باعث می‌شه مثل کد "ترتیبی" معمولی به نظر بیاد و توی لحظه‌های درست "انتظار" رو برات انجام بده. + +وقتی یه عملیاتی هست که قبل از دادن نتیجه‌ها نیاز به انتظار داره و از این قابلیت‌های جدید پایتون پشتیبانی می‌کنه، می‌تونی اینجوری کدنویسیش کنی: + +```Python +burgers = await get_burgers(2) +``` + +نکته کلیدی اینجا `await` هست. به پایتون می‌گه که باید ⏸ منتظر بمونه تا `get_burgers(2)` کارش 🕙 تموم بشه قبل از اینکه نتیجه‌ها رو توی `burgers` ذخیره کنه. با این، پایتون می‌دونه که می‌تونه بره یه کار دیگه 🔀 ⏯ توی این مدت بکنه (مثل گرفتن یه درخواست دیگه). + +برای اینکه `await` کار کنه، باید توی یه تابع باشه که از این ناهم‌زمانی پشتیبانی کنه. برای این کار، فقط با `async def` تعریفش می‌کنی: + +```Python hl_lines="1" +async def get_burgers(number: int): + # یه سری کار ناهم‌زمان برای ساختن برگرها انجام بده + return burgers +``` + +...به جای `def`: + +```Python hl_lines="2" +# این ناهم‌زمان نیست +def get_sequential_burgers(number: int): + # یه سری کار ترتیبی برای ساختن برگرها انجام بده + return burgers +``` + +با `async def`، پایتون می‌دونه که توی اون تابع باید حواسش به عبارت‌های `await` باشه، و می‌تونه اجرای اون تابع رو "موقتاً متوقف" ⏸ کنه و بره یه کار دیگه 🔀 قبل از برگشتن بکنه. + +وقتی می‌خوای یه تابع `async def` رو صدا کنی، باید "منتظرش" بمونی. پس این کار نمی‌کنه: + +```Python +# این کار نمی‌کنه، چون get_burgers با async def تعریف شده +burgers = get_burgers(2) +``` + +--- + +پس، اگه از یه کتابخونه استفاده می‌کنی که بهت می‌گه می‌تونی با `await` صداش کنی، باید *توابع عملیات مسیرت* که ازش استفاده می‌کنن رو با `async def` بسازی، مثل: + +```Python hl_lines="2-3" +@app.get('/burgers') +async def read_burgers(): + burgers = await get_burgers(2) + return burgers +``` + +### جزئیات فنی‌تر + +شاید متوجه شده باشی که `await` فقط توی توابعی که با `async def` تعریف شدن می‌تونه استفاده بشه. + +ولی در عین حال، توابعی که با `async def` تعریف شدن باید "منتظر"شون بمونی. پس توابع با `async def` فقط توی توابعی که با `async def` تعریف شدن می‌تونن صدا زده بشن. + +حالا، قضیه مرغ و تخم‌مرغ چیه، چطور اولین تابع `async` رو صدا می‌کنی؟ + +اگه با **FastAPI** کار می‌کنی، لازم نیست نگران این باشی، چون اون "اولین" تابع، *تابع عملیات مسیرت* هست، و FastAPI می‌دونه چطور کار درست رو بکنه. + +ولی اگه بخوای بدون FastAPI از `async` / `await` استفاده کنی، اینم ممکنه. + +### کد ناهم‌زمان خودت رو بنویس + +Starlette (و **FastAPI**) بر پایه AnyIO هستن، که باعث می‌شه با کتابخونه استاندارد پایتون asyncio و Trio سازگار باشه. + +به‌خصوص، می‌تونی مستقیماً از AnyIO برای موارد استفاده پیشرفته هم‌زمانی که نیاز به الگوهای پیچیده‌تر توی کد خودت دارن استفاده کنی. + +و حتی اگه از FastAPI استفاده نکنی، می‌تونی برنامه‌های ناهم‌زمان خودت رو با AnyIO بنویسی تا خیلی سازگار باشه و فوایدش رو بگیری (مثل *هم‌زمانی ساختاریافته*). + +من یه کتابخونه دیگه روی AnyIO ساختم، یه لایه نازک روش، تا یه کم annotationهای نوع رو بهتر کنم و **تکمیل خودکار** بهتر، **خطاهای درون‌خطی** و غیره بگیرم. یه مقدمه و آموزش ساده هم داره که بهت کمک می‌کنه **بفهمی** و **کد ناهم‌زمان خودت رو بنویسی**: Asyncer. اگه بخوای **کد ناهم‌زمان رو با کد معمولی** (بلاک‌کننده/هم‌زمان) ترکیب کنی خیلی به‌دردت می‌خوره. + +### شکل‌های دیگه کد ناهم‌زمان + +این سبک استفاده از `async` و `await` توی زبون نسبتاً جدیده. + +ولی کار با کد ناهم‌زمان رو خیلی ساده‌تر می‌کنه. + +همین سینتکس (یا تقریباً یکسان) اخیراً توی نسخه‌های مدرن جاوااسکریپت (توی مرورگر و NodeJS) هم اضافه شده. + +ولی قبل از اون، مدیریت کد ناهم‌زمان خیلی پیچیده‌تر و سخت‌تر بود. + +توی نسخه‌های قبلی پایتون، می‌تونستی از نخ‌ها یا Gevent استفاده کنی. ولی کد خیلی پیچیده‌تر می‌شه برای فهمیدن، دیباگ کردن و فکر کردن بهش. + +توی نسخه‌های قبلی NodeJS / جاوااسکریپت مرورگر، از "کال‌بک‌ها" استفاده می‌کردی. که می‌رسید به جهان کال‌بک‌ها. + +## کروتین‌ها + +**کروتین** فقط یه اصطلاح خیلی شیک برای چیزیه که یه تابع `async def` برمی‌گردونه. پایتون می‌دونه که این یه چیزی مثل تابع هست، می‌تونه شروع بشه و یه جایی تموم بشه، ولی ممکنه داخلش هم موقف ⏸ بشه، هر وقت یه `await` توش باشه. + +ولی همه این قابلیت استفاده از کد ناهم‌زمان با `async` و `await` خیلی وقتا خلاصه می‌شه به استفاده از "کروتین‌ها". این قابل مقایسه با ویژگی اصلی Go، یعنی "Goroutineها" هست. + +## نتیجه‌گیری + +بیاید همون جمله از بالا رو ببینیم: + +> نسخه‌های مدرن پایتون از **"کد ناهم‌زمان"** با چیزی که بهش **"کروتین"** می‌گن پشتیبانی می‌کنن، با سینتکس **`async` و `await`**. + +حالا باید بیشتر برات معنی بده. ✨ + +همه اینا چیزیه که به FastAPI (از طریق Starlette) قدرت می‌ده و باعث می‌شه عملکرد چشمگیری داشته باشه. + +## جزئیات خیلی فنی + +/// warning + +احتمالاً می‌تونی اینو رد کنی. + +اینا جزئیات خیلی فنی از نحوه کار **FastAPI** زیر پوسته‌ست. + +اگه یه کم دانش فنی (کروتین‌ها، نخ‌ها، بلاک کردن و غیره) داری و کنجکاوی که FastAPI چطور `async def` رو در مقابل `def` معمولی مدیریت می‌کنه، ادامه بده. + +/// + +### توابع عملیات مسیر + +وقتی یه *تابع عملیات مسیر* رو با `def` معمولی به جای `async def` تعریف می‌کنی، توی یه استخر نخ خارجی اجرا می‌شه که بعدش منتظرش می‌مونن، به جای اینکه مستقیم صداش کنن (چون سرور رو بلاک می‌کنه). + +اگه از یه فریم‌ورک ناهم‌زمان دیگه میای که به روش بالا کار نمی‌کنه و عادت داری *توابع عملیات مسیر* ساده فقط محاسباتی رو با `def` معمولی برای یه سود کوچیک عملکرد (حدود 100 نانوثانیه) تعریف کنی، توجه کن که توی **FastAPI** اثرش کاملاً برعکسه. توی این موارد، بهتره از `async def` استفاده کنی مگه اینکه *توابع عملیات مسیرت* کدی داشته باشن که عملیات I/O بلاک‌کننده انجام بده. + +با این حال، توی هر دو موقعیت، احتمالش زیاده که **FastAPI** هنوز [سریع‌تر](index.md#performance){.internal-link target=_blank} از فریم‌ورک قبلی‌ات باشه (یا حداقل قابل مقایسه باهاش). + +### وابستگی‌ها + +همین برای [وابستگی‌ها](tutorial/dependencies/index.md){.internal-link target=_blank} هم صدق می‌کنه. اگه یه وابستگی یه تابع `def` معمولی به جای `async def` باشه، توی استخر نخ خارجی اجرا می‌شه. + +### زیروابستگی‌ها + +می‌تونی چند تا وابستگی و [زیروابستگی](tutorial/dependencies/sub-dependencies.md){.internal-link target=_blank} داشته باشی که همدیگه رو نیاز دارن (به‌عنوان پارامترهای تعریف تابع)، بعضی‌هاشون ممکنه با `async def` ساخته بشن و بعضی‌ها با `def` معمولی. بازم کار می‌کنه، و اونایی که با `def` معمولی ساخته شدن توی یه نخ خارجی (از استخر نخ) صدا زده می‌شن به جای اینکه "منتظرشون" بمونن. + +### توابع کاربردی دیگه + +هر تابع کاربردی دیگه‌ای که مستقیم خودت صداش می‌کنی می‌تونه با `def` معمولی یا `async def` ساخته بشه و FastAPI رو نحوه صدازدنش تأثیر نمی‌ذاره. + +این برخلاف توابعی هست که FastAPI برات صداشون می‌کنه: *توابع عملیات مسیر* و وابستگی‌ها. + +اگه تابع کاربردیت یه تابع معمولی با `def` باشه، مستقیم صداش می‌کنن (همون‌طور که توی کدت نوشتی)، نه توی استخر نخ، اگه تابع با `async def` ساخته شده باشه، باید وقتی توی کدت صداش می‌کنی `await`ش کنی. + +--- + +دوباره، اینا جزئیات خیلی فنی هستن که احتمالاً اگه دنبالشون اومده باشی برات مفید باشن. + +وگرنه، با راهنمایی‌های بخش بالا باید خوب باشی: عجله داری؟. diff --git a/docs/fa/docs/learn/index.md b/docs/fa/docs/learn/index.md new file mode 100644 index 000000000..06aa7f00e --- /dev/null +++ b/docs/fa/docs/learn/index.md @@ -0,0 +1,5 @@ +# یادگیری + +اینجا بخش‌های مقدماتی و آموزش‌هایی هستن که برای یادگیری **FastAPI** بهت کمک می‌کنن. + +می‌تونی اینو یه **کتاب**، یه **دوره آموزشی**، یا راه **رسمی** و پیشنهادی برای یادگیری FastAPI در نظر بگیری. 😎 diff --git a/docs/fa/docs/python-types.md b/docs/fa/docs/python-types.md new file mode 100644 index 000000000..c428acbf7 --- /dev/null +++ b/docs/fa/docs/python-types.md @@ -0,0 +1,578 @@ +# مقدمه‌ای بر انواع نوع در پایتون + +پایتون از "نوع‌نما"های اختیاری (که بهشون "type hints" یا "type annotations" هم می‌گن) پشتیبانی می‌کنه. + +این **"نوع‌نماها"** یا annotationها یه سینتکس خاص هستن که بهت اجازه می‌دن نوع یه متغیر رو مشخص کنی. + +با مشخص کردن نوع متغیرها، ویرایشگرها و ابزارها می‌تونن پشتیبانی بهتری بهت بدن. + +این فقط یه **آموزش سریع / یادآوری** در مورد نوع‌نماهای پایتونه. فقط حداقل چیزایی که برای استفاده ازشون با **FastAPI** لازمه رو پوشش می‌ده... که در واقع خیلی کمه. + +**FastAPI** کاملاً بر پایه این نوع‌نماهاست و این بهش کلی مزیت و فایده می‌ده. + +ولی حتی اگه هیچ‌وقت از **FastAPI** استفاده نکنی، بازم یادگیری یه کم در موردشون به نفعته. + +/// note + +اگه حرفه‌ای پایتونی و همه‌چیز رو در مورد نوع‌نماها می‌دونی، برو سراغ فصل بعدی. + +/// + +## انگیزه + +بیاید با یه مثال ساده شروع کنیم: + +{* ../../docs_src/python_types/tutorial001.py *} + +وقتی این برنامه رو اجرا کنی، خروجی اینه: + +``` +John Doe +``` + +این تابع این کارا رو می‌کنه: + +* یه `first_name` و `last_name` می‌گیره. +* حرف اول هر کدوم رو با `title()` بزرگ می‌کنه. +* ترکیبشون می‌کنه با یه فاصله وسطشون. + +{* ../../docs_src/python_types/tutorial001.py hl[2] *} + +### ویرایشش کن + +این یه برنامه خیلی ساده‌ست. + +ولی حالا تصور کن داری از صفر می‌نویسیش. + +یه جایی شروع کردی به تعریف تابع، پارامترهات آماده‌ست... + +ولی بعد باید "اون متدی که حرف اول رو بزرگ می‌کنه" رو صدا کنی. + +آیا اسمش `upper` بود؟ یا `uppercase`؟ شاید `first_uppercase`؟ یا `capitalize`؟ + +بعد، با دوست قدیمی برنامه‌نویسا، تکمیل خودکار ویرایشگر، امتحان می‌کنی. + +پارامتر اول تابع، `first_name` رو تایپ می‌کنی، بعد یه نقطه (`.`) می‌ذاری و `Ctrl+Space` رو می‌زنی تا تکمیل خودکار بیاد. + +ولی متأسفانه، چیز مفیدی نمی‌گیری: + + + +### نوع اضافه کن + +بیا فقط یه خط از نسخه قبلی رو تغییر بدیم. + +دقیقاً این بخش، پارامترهای تابع رو، از: + +```Python + first_name, last_name +``` + +به: + +```Python + first_name: str, last_name: str +``` + +عوض می‌کنیم. + +همینه. + +اینا همون "نوع‌نماها" هستن: + +{* ../../docs_src/python_types/tutorial002.py hl[1] *} + +این با تعریف مقدار پیش‌فرض فرق داره، مثل: + +```Python + first_name="john", last_name="doe" +``` + +یه چیز متفاوته. + +ما از دونقطه (`:`) استفاده می‌کنیم، نه علامت مساوی (`=`)‌. + +و اضافه کردن نوع‌نماها معمولاً چیزی که اتفاق می‌افته رو از چیزی که بدون اونا می‌افتاد تغییر نمی‌ده. + +ولی حالا، دوباره تصور کن وسط ساختن اون تابع هستی، ولی این بار با نوع‌نماها. + +توی همون نقطه، سعی می‌کنی تکمیل خودکار رو با `Ctrl+Space` فعال کنی و اینو می‌بینی: + + + +با این، می‌تونی اسکرول کنی، گزینه‌ها رو ببینی، تا وقتی که اون چیزی که "به نظرت آشنا میاد" رو پیدا کنی: + + + +## انگیزه بیشتر + +این تابع رو چک کن، الان نوع‌نما داره: + +{* ../../docs_src/python_types/tutorial003.py hl[1] *} + +چون ویرایشگر نوع متغیرها رو می‌دونه، فقط تکمیل خودکار نمی‌گیری، بلکه چک خطاها هم داری: + + + +حالا می‌دونی که باید درستش کنی، `age` رو با `str(age)` به یه رشته تبدیل کنی: + +{* ../../docs_src/python_types/tutorial004.py hl[2] *} + +## تعریف نوع‌ها + +تازه اصلی‌ترین جا برای تعریف نوع‌نماها رو دیدی. به‌عنوان پارامترهای تابع. + +این هم اصلی‌ترین جاییه که با **FastAPI** ازشون استفاده می‌کنی. + +### نوع‌های ساده + +می‌تونی همه نوع‌های استاندارد پایتون رو تعریف کنی، نه فقط `str`. + +مثلاً می‌تونی از اینا استفاده کنی: + +* `int` +* `float` +* `bool` +* `bytes` + +{* ../../docs_src/python_types/tutorial005.py hl[1] *} + +### نوع‌های عمومی با پارامترهای نوع + +یه سری ساختار داده هستن که می‌تونن مقدارهای دیگه رو نگه دارن، مثل `dict`، `list`، `set` و `tuple`. و مقدارهای داخلیشون هم می‌تونن نوع خودشون رو داشته باشن. + +به این نوع‌ها که نوع‌های داخلی دارن می‌گن "**عمومی**" یا "generic". و می‌شه اونا رو تعریف کرد، حتی با نوع‌های داخلیشون. + +برای تعریف این نوع‌ها و نوع‌های داخلیشون، می‌تونی از ماژول استاندارد پایتون `typing` استفاده کنی. این ماژول مخصوص پشتیبانی از نوع‌نماهاست. + +#### نسخه‌های جدیدتر پایتون + +سینتکس با استفاده از `typing` با همه نسخه‌ها، از پایتون 3.6 تا جدیدترین‌ها، از جمله پایتون 3.9، 3.10 و غیره **سازگاره**. + +با پیشرفت پایتون، **نسخه‌های جدیدتر** پشتیبانی بهتری برای این نوع‌نماها دارن و توی خیلی موارد حتی لازم نیست ماژول `typing` رو وارد کنی و ازش برای تعریف نوع‌نماها استفاده کنی. + +اگه بتونی برای پروژه‌ات از یه نسخه جدیدتر پایتون استفاده کنی، می‌تونی از این سادگی اضافه بهره ببری. + +توی همه مستندات، مثال‌هایی هستن که با هر نسخه پایتون سازگارن (وقتی تفاوتی هست). + +مثلاً "**Python 3.6+**" یعنی با پایتون 3.6 یا بالاتر (مثل 3.7، 3.8، 3.9، 3.10 و غیره) سازگاره. و "**Python 3.9+**" یعنی با پایتون 3.9 یا بالاتر (مثل 3.10 و غیره) سازگاره. + +اگه بتونی از **جدیدترین نسخه‌های پایتون** استفاده کنی، از مثال‌های نسخه آخر استفاده کن، چون اونا **بهترین و ساده‌ترین سینتکس** رو دارن، مثلاً "**Python 3.10+**". + +#### لیست + +مثلاً، بیایم یه متغیر تعریف کنیم که یه `list` از `str` باشه. + +//// tab | Python 3.9+ + +متغیر رو با همون سینتکس دونقطه (`:`) تعریف کن. + +به‌عنوان نوع، `list` رو بذار. + +چون لیست یه نوعه که نوع‌های داخلی داره، اونا رو توی کروشه‌ها می‌ذاری: + +```Python hl_lines="1" +{!> ../../docs_src/python_types/tutorial006_py39.py!} +``` + +//// + +//// tab | Python 3.8+ + +از `typing`، `List` رو (با `L` بزرگ) وارد کن: + +```Python hl_lines="1" +{!> ../../docs_src/python_types/tutorial006.py!} +``` + +متغیر رو با همون سینتکس دونقطه (`:`) تعریف کن. + +به‌عنوان نوع، `List` رو که از `typing` وارد کردی بذار. + +چون لیست یه نوعه که نوع‌های داخلی داره، اونا رو توی کروشه‌ها می‌ذاری: + +```Python hl_lines="4" +{!> ../../docs_src/python_types/tutorial006.py!} +``` + +//// + +/// info + +اون نوع‌های داخلی توی کروشه‌ها بهشون "پارامترهای نوع" می‌گن. + +توی این مورد، `str` پارامتر نوعیه که به `List` (یا `list` توی پایتون 3.9 و بالاتر) پاس داده شده. + +/// + +یعنی: "متغیر `items` یه `list` هست، و هر کدوم از آیتم‌های این لیست یه `str` هستن". + +/// tip + +اگه از پایتون 3.9 یا بالاتر استفاده می‌کنی، لازم نیست `List` رو از `typing` وارد کنی، می‌تونی همون نوع معمولی `list` رو به جاش استفاده کنی. + +/// + +با این کار، ویرایشگرت حتی وقتی داری آیتم‌های لیست رو پردازش می‌کنی بهت کمک می‌کنه: + + + +بدون نوع‌ها، رسیدن به این تقریباً غیرممکنه. + +توجه کن که متغیر `item` یکی از عناصر توی لیست `items` هست. + +و با این حال، ویرایشگر می‌دونه که یه `str` هست و براش پشتیبانی می‌ده. + +#### تاپل و ست + +برای تعریف `tuple`ها و `set`ها هم همین کار رو می‌کنی: + +//// tab | Python 3.9+ + +```Python hl_lines="1" +{!> ../../docs_src/python_types/tutorial007_py39.py!} +``` + +//// + +//// tab | Python 3.8+ + +```Python hl_lines="1 4" +{!> ../../docs_src/python_types/tutorial007.py!} +``` + +//// + +یعنی: + +* متغیر `items_t` یه `tuple` با 3 تا آیتمه، یه `int`، یه `int` دیگه، و یه `str`. +* متغیر `items_s` یه `set` هست، و هر کدوم از آیتم‌هاش از نوع `bytes` هستن. + +#### دیکشنری + +برای تعریف یه `dict`، 2 تا پارامتر نوع می‌دی، که با کاما از هم جدا شدن. + +پارامتر نوع اول برای کلیدهای `dict` هست. + +پارامتر نوع دوم برای مقدارهای `dict` هست: + +//// tab | Python 3.9+ + +```Python hl_lines="1" +{!> ../../docs_src/python_types/tutorial008_py39.py!} +``` + +//// + +//// tab | Python 3.8+ + +```Python hl_lines="1 4" +{!> ../../docs_src/python_types/tutorial008.py!} +``` + +//// + +یعنی: + +* متغیر `prices` یه `dict` هست: + * کلیدهای این `dict` از نوع `str` هستن (مثلاً اسم هر آیتم). + * مقدارهای این `dict` از نوع `float` هستن (مثلاً قیمت هر آیتم). + +#### اتحادیه + +می‌تونی تعریف کنی که یه متغیر می‌تونه هر کدوم از **چند تا نوع** باشه، مثلاً یه `int` یا یه `str`. + +توی پایتون 3.6 و بالاتر (از جمله پایتون 3.10) می‌تونی از نوع `Union` توی `typing` استفاده کنی و نوع‌های ممکن رو توی کروشه‌ها بذاری. + +توی پایتون 3.10 یه **سینتکس جدید** هم هست که می‌تونی نوع‌های ممکن رو با یه خط عمودی (`|`) جدا کنی. + +//// tab | Python 3.10+ + +```Python hl_lines="1" +{!> ../../docs_src/python_types/tutorial008b_py310.py!} +``` + +//// + +//// tab | Python 3.8+ + +```Python hl_lines="1 4" +{!> ../../docs_src/python_types/tutorial008b.py!} +``` + +//// + +توی هر دو حالت یعنی `item` می‌تونه یه `int` یا یه `str` باشه. + +#### شاید `None` + +می‌تونی تعریف کنی که یه مقدار می‌تونه یه نوع باشه، مثلاً `str`، ولی می‌تونه `None` هم باشه. + +توی پایتون 3.6 و بالاتر (از جمله پایتون 3.10) می‌تونی با وارد کردن و استفاده از `Optional` از ماژول `typing` اینو تعریف کنی. + +```Python hl_lines="1 4" +{!../../docs_src/python_types/tutorial009.py!} +``` + +استفاده از `Optional[str]` به جای فقط `str` به ویرایشگر کمک می‌کنه خطاهایی که ممکنه فکر کنی یه مقدار همیشه `str` هست رو پیدا کنه، در حالی که می‌تونه `None` هم باشه. + +`Optional[Something]` در واقع میان‌بر برای `Union[Something, None]` هست، این دو تا معادلن. + +یعنی توی پایتون 3.10، می‌تونی از `Something | None` استفاده کنی: + +//// tab | Python 3.10+ + +```Python hl_lines="1" +{!> ../../docs_src/python_types/tutorial009_py310.py!} +``` + +//// + +//// tab | Python 3.8+ + +```Python hl_lines="1 4" +{!> ../../docs_src/python_types/tutorial009.py!} +``` + +//// + +//// tab | Python 3.8+ جایگزین + +```Python hl_lines="1 4" +{!> ../../docs_src/python_types/tutorial009b.py!} +``` + +//// + +#### استفاده از `Union` یا `Optional` + +اگه از نسخه پایتون زیر 3.10 استفاده می‌کنی، یه نکته از دید خیلی **شخصی** خودم: + +* 🚨 از `Optional[SomeType]` استفاده نکن +* به جاش ✨ **از `Union[SomeType, None]` استفاده کن** ✨. + +هر دو معادلن و زیر پوسته یکی‌ان، ولی من `Union` رو به `Optional` ترجیح می‌دم چون کلمه "**اختیاری**" انگار暗示 می‌کنه که مقدار اختیاریه، در حالی که در واقع یعنی "می‌تونه `None` باشه"، حتی اگه اختیاری نباشه و هنوز لازم باشه. + +فکر می‌کنم `Union[SomeType, None]` واضح‌تر نشون می‌ده چی معنی می‌ده. + +فقط بحث کلمات و اسم‌هاست. ولی این کلمات می‌تونن رو طرز فکر تو و تیمت نسبت به کد تأثیر بذارن. + +به‌عنوان مثال، این تابع رو ببین: + +{* ../../docs_src/python_types/tutorial009c.py hl[1,4] *} + +پارامتر `name` به‌عنوان `Optional[str]` تعریف شده، ولی **اختیاری نیست**، نمی‌تونی تابع رو بدون پارامتر صدا کنی: + +```Python +say_hi() # اوه نه، این خطا می‌ده! 😱 +``` + +پارامتر `name` **هنوز لازمه** (نه *اختیاری*) چون مقدار پیش‌فرض نداره. با این حال، `name` مقدار `None` رو قبول می‌کنه: + +```Python +say_hi(name=None) # این کار می‌کنه، None معتبره 🎉 +``` + +خبر خوب اینه که وقتی رو پایتون 3.10 باشی، لازم نیست نگران این باشی، چون می‌تونی به‌سادگی از `|` برای تعریف اتحادیه نوع‌ها استفاده کنی: + +{* ../../docs_src/python_types/tutorial009c_py310.py hl[1,4] *} + +اون موقع دیگه لازم نیست نگران اسم‌هایی مثل `Optional` و `Union` باشی. 😎 + +#### نوع‌های عمومی + +این نوع‌هایی که پارامترهای نوع رو توی کروشه‌ها می‌گیرن بهشون **نوع‌های عمومی** یا **Generics** می‌گن، مثلاً: + +//// tab | Python 3.10+ + +می‌تونی از همون نوع‌های داخلی به‌عنوان نوع‌های عمومی استفاده کنی (با کروشه‌ها و نوع‌ها داخلشون): + +* `list` +* `tuple` +* `set` +* `dict` + +و همون‌طور که توی پایتون 3.8 بود، از ماژول `typing`: + +* `Union` +* `Optional` (همون‌طور که توی پایتون 3.8 بود) +* ...و بقیه. + +توی پایتون 3.10، به‌عنوان جایگزین برای استفاده از نوع‌های عمومی `Union` و `Optional`، می‌تونی از خط عمودی (`|`) برای تعریف اتحادیه نوع‌ها استفاده کنی، که خیلی بهتر و ساده‌تره. + +//// + +//// tab | Python 3.9+ + +می‌تونی از همون نوع‌های داخلی به‌عنوان نوع‌های عمومی استفاده کنی (با کروشه‌ها و نوع‌ها داخلشون): + +* `list` +* `tuple` +* `set` +* `dict` + +و همون‌طور که توی پایتون 3.8 بود، از ماژول `typing`: + +* `Union` +* `Optional` +* ...و بقیه. + +//// + +//// tab | Python 3.8+ + +* `List` +* `Tuple` +* `Set` +* `Dict` +* `Union` +* `Optional` +* ...و بقیه. + +//// + +### کلاس‌ها به‌عنوان نوع + +می‌تونی یه کلاس رو هم به‌عنوان نوع یه متغیر تعریف کنی. + +فرض کن یه کلاس `Person` داری، با یه نام: + +{* ../../docs_src/python_types/tutorial010.py hl[1:3] *} + +بعد می‌تونی یه متغیر رو از نوع `Person` تعریف کنی: + +{* ../../docs_src/python_types/tutorial010.py hl[6] *} + +و بعد، دوباره، همه پشتیبانی ویرایشگر رو داری: + + + +توجه کن که این یعنی "`one_person` یه **نمونه** از کلاس `Person` هست". + +یعنی "`one_person` خود **کلاس** به اسم `Person` نیست". + +## مدل‌های Pydantic + +Pydantic یه کتابخونه پایتونه برای اعتبارسنجی داده‌ها. + +"شکل" داده‌ها رو به‌عنوان کلاس‌هایی با ویژگی‌ها تعریف می‌کنی. + +و هر ویژگی یه نوع داره. + +بعد یه نمونه از اون کلاس رو با یه سری مقدار می‌سازی و اون مقدارها رو اعتبارسنجی می‌کنه، به نوع مناسب تبدیلشون می‌کنه (اگه لازم باشه) و یه شیء با همه داده‌ها بهت می‌ده. + +و با اون شیء نهایی همه پشتیبانی ویرایشگر رو می‌گیری. + +یه مثال از مستندات رسمی Pydantic: + +//// tab | Python 3.10+ + +```Python +{!> ../../docs_src/python_types/tutorial011_py310.py!} +``` + +//// + +//// tab | Python 3.9+ + +```Python +{!> ../../docs_src/python_types/tutorial011_py39.py!} +``` + +//// + +//// tab | Python 3.8+ + +```Python +{!> ../../docs_src/python_types/tutorial011.py!} +``` + +//// + +/// info + +برای اطلاعات بیشتر در مورد Pydantic، مستنداتش رو چک کن. + +/// + +**FastAPI** کاملاً بر پایه Pydantic هست. + +توی [آموزش - راهنمای کاربر](tutorial/index.md){.internal-link target=_blank} خیلی بیشتر از اینا رو توی عمل می‌بینی. + +/// tip + +Pydantic یه رفتار خاص داره وقتی از `Optional` یا `Union[Something, None]` بدون مقدار پیش‌فرض استفاده می‌کنی، می‌تونی توی مستندات Pydantic در مورد فیلدهای اختیاری لازم بیشتر بخونی. + +/// + +## نوع‌نماها با Annotationهای متادیتا + +پایتون یه قابلیت هم داره که بهت اجازه می‌ده **متادیتا اضافی** رو توی این نوع‌نماها بذاری با استفاده از `Annotated`. + +//// tab | Python 3.9+ + +توی پایتون 3.9، `Annotated` بخشی از کتابخونه استاندارده، پس می‌تونی از `typing` واردش کنی. + +```Python hl_lines="1 4" +{!> ../../docs_src/python_types/tutorial013_py39.py!} +``` + +//// + +//// tab | Python 3.8+ + +توی نسخه‌های زیر پایتون 3.9، `Annotated` رو از `typing_extensions` وارد می‌کنی. + +با **FastAPI** از قبل نصب شده. + +```Python hl_lines="1 4" +{!> ../../docs_src/python_types/tutorial013.py!} +``` + +//// + +خود پایتون با این `Annotated` کاری نمی‌کنه. و برای ویرایشگرها و ابزارهای دیگه، نوع هنوز `str` هست. + +ولی می‌تونی از این فضا توی `Annotated` استفاده کنی تا به **FastAPI** متادیتای اضافی در مورد اینکه چطور می‌خوای برنامه‌ات رفتار کنه بدی. + +نکته مهم اینه که **اولین *پارامتر نوع*** که به `Annotated` می‌دی، **نوع واقعی** هست. بقیش فقط متادیتا برای ابزارهای دیگه‌ست. + +الان فقط باید بدونی که `Annotated` وجود داره، و اینکه پایتون استاندارده. 😎 + +بعداً می‌بینی که چقدر **قوی** می‌تونه باشه. + +/// tip + +اینکه این **پایتون استاندارده** یعنی هنوز **بهترین تجربه توسعه‌دهنده** رو توی ویرایشگرت، با ابزارهایی که برای تحلیل و بازسازی کدت استفاده می‌کنی و غیره می‌گیری. ✨ + +و همین‌طور کدت با خیلی از ابزارها و کتابخونه‌های دیگه پایتون خیلی سازگار می‌مونه. 🚀 + +/// + +## نوع‌نماها توی **FastAPI** + +**FastAPI** از این نوع‌نماها استفاده می‌کنه تا چند تا کار بکنه. + +با **FastAPI** پارامترها رو با نوع‌نماها تعریف می‌کنی و اینا رو می‌گیری: + +* **پشتیبانی ویرایشگر**. +* **چک نوع‌ها**. + +...و **FastAPI** از همون تعریف‌ها برای اینا استفاده می‌کنه: + +* **تعریف نیازها**: از پارامترهای مسیر درخواست، پارامترهای کوئری، هدرها، بدنه‌ها، وابستگی‌ها و غیره. +* **تبدیل داده**: از درخواست به نوع مورد نیاز. +* **اعتبارسنجی داده**: که از هر درخواست میاد: + * تولید **خطاهای خودکار** که به کلاینت برمی‌گرده وقتی داده نامعتبره. +* **مستندسازی** API با استفاده از OpenAPI: + * که بعدش توسط رابط‌های کاربری مستندات تعاملی خودکار استفاده می‌شه. + +اینا شاید همه‌ش انتزاعی به نظر بیاد. نگران نباش. همه اینا رو توی عمل توی [آموزش - راهنمای کاربر](tutorial/index.md){.internal-link target=_blank} می‌بینی. + +نکته مهم اینه که با استفاده از نوع‌های استاندارد پایتون، توی یه جا (به جای اضافه کردن کلاس‌های بیشتر، دکوراتورها و غیره)، **FastAPI** کلی از کار رو برات انجام می‌ده. + +/// info + +اگه همه آموزش رو گذروندی و برگشتی که بیشتر در مورد نوع‌ها ببینی، یه منبع خوب "تقلب‌نامه" از `mypy` هست. + +/// diff --git a/docs/ja/docs/tutorial/body-fields.md b/docs/ja/docs/tutorial/body-fields.md index 0466320f1..ce5630351 100644 --- a/docs/ja/docs/tutorial/body-fields.md +++ b/docs/ja/docs/tutorial/body-fields.md @@ -44,7 +44,7 @@ 追加情報は`Field`や`Query`、`Body`などで宣言することができます。そしてそれは生成されたJSONスキーマに含まれます。 -後に例を用いて宣言を学ぶ際に、追加情報を句悪方法を学べます。 +後に例を用いて宣言を学ぶ際に、追加情報を追加する方法を学べます。 ## まとめ diff --git a/docs/ja/docs/tutorial/encoder.md b/docs/ja/docs/tutorial/encoder.md index 409ebeec6..309cf8857 100644 --- a/docs/ja/docs/tutorial/encoder.md +++ b/docs/ja/docs/tutorial/encoder.md @@ -8,7 +8,7 @@ ## `jsonable_encoder`の使用 -JSON互換のデータのみを受信するデータベース`fase_db`があるとしましょう。 +JSON互換のデータのみを受信するデータベース`fake_db`があるとしましょう。 例えば、`datetime`オブジェクトはJSONと互換性がないので、このデーターベースには受け取られません。 diff --git a/docs/ja/docs/tutorial/handling-errors.md b/docs/ja/docs/tutorial/handling-errors.md index 9a46cc738..37315b087 100644 --- a/docs/ja/docs/tutorial/handling-errors.md +++ b/docs/ja/docs/tutorial/handling-errors.md @@ -63,7 +63,7 @@ Pythonの例外なので、`return`ではなく、`raise`です。 `HTTPException`を発生させる際には、`str`だけでなく、JSONに変換できる任意の値を`detail`パラメータとして渡すことができます。 -`dist`や`list`などを渡すことができます。 +`dict`や`list`などを渡すことができます。 これらは **FastAPI** によって自動的に処理され、JSONに変換されます。 diff --git a/docs/pt/docs/advanced/generate-clients.md b/docs/pt/docs/advanced/generate-clients.md index 04d7c0071..dc6b29511 100644 --- a/docs/pt/docs/advanced/generate-clients.md +++ b/docs/pt/docs/advanced/generate-clients.md @@ -22,7 +22,7 @@ E isso mostra o verdadeiro compromisso deles com o FastAPI e sua **comunidade** Por exemplo, você pode querer experimentar: -* Speakeasy +* Speakeasy * Stainless * liblab diff --git a/docs/pt/docs/project-generation.md b/docs/pt/docs/project-generation.md index e5c935fd2..e337ad762 100644 --- a/docs/pt/docs/project-generation.md +++ b/docs/pt/docs/project-generation.md @@ -1,84 +1,28 @@ -# Geração de Projetos - Modelo - -Você pode usar um gerador de projetos para começar, por já incluir configurações iniciais, segurança, banco de dados e os primeiros _endpoints_ API já feitos para você. - -Um gerador de projetos sempre terá uma pré-configuração que você pode atualizar e adaptar para suas próprias necessidades, mas pode ser um bom ponto de partida para seu projeto. - -## Full Stack FastAPI PostgreSQL - -GitHub: https://github.com/tiangolo/full-stack-fastapi-postgresql - -### Full Stack FastAPI PostgreSQL - Recursos - -* Integração completa **Docker**. -* Modo de implantação Docker Swarm. -* Integração e otimização **Docker Compose** para desenvolvimento local. -* **Pronto para Produção** com servidor _web_ usando Uvicorn e Gunicorn. -* _Backend_ **FastAPI** Python: - * **Rápido**: Alta performance, no nível de **NodeJS** e **Go** (graças ao Starlette e Pydantic). - * **Intuitivo**: Ótimo suporte de editor. _Auto-Complete_ em todo lugar. Menos tempo _debugando_. - * **Fácil**: Projetado para ser fácil de usar e aprender. Menos tempo lendo documentações. - * **Curto**: Minimize duplicação de código. Múltiplos recursos para cada declaração de parâmetro. - * **Robusto**: Tenha código pronto para produção. Com documentação interativa automática. - * **Baseado em Padrões**: Baseado em (e completamente compatível com) padrões abertos para APIs: OpenAPI e JSON Schema. - * **Muitos outros recursos** incluindo validação automática, serialização, documentação interativa, autenticação com _tokens_ OAuth2 JWT etc. -* **Senha segura** _hashing_ por padrão. -* Autenticação **Token JWT**. -* Modelos **SQLAlchemy** (independente de extensões Flask, para que eles possam ser usados com _workers_ Celery diretamente). -* Modelos básicos para usuários (modifique e remova conforme suas necessidades). -* Migrações **Alembic**. -* **CORS** (_Cross Origin Resource Sharing_ - Compartilhamento de Recursos Entre Origens). -* _Worker_ **Celery** que pode importar e usar modelos e códigos do resto do _backend_ seletivamente. -* Testes _backend_ _REST_ baseados no **Pytest**, integrados com Docker, então você pode testar a interação completa da API, independente do banco de dados. Como roda no Docker, ele pode construir um novo repositório de dados do zero toda vez (assim você pode usar ElasticSearch, MongoDB, CouchDB, ou o que quiser, e apenas testar que a API esteja funcionando). -* Fácil integração com Python através dos **Kernels Jupyter** para desenvolvimento remoto ou no Docker com extensões como Atom Hydrogen ou Visual Studio Code Jupyter. -* _Frontend_ **Vue**: - * Gerado com Vue CLI. - * Controle de **Autenticação JWT**. - * Visualização de _login_. - * Após o _login_, visualização do painel de controle principal. - * Painel de controle principal com criação e edição de usuário. - * Edição do próprio usuário. - * **Vuex**. - * **Vue-router**. - * **Vuetify** para belos componentes _material design_. - * **TypeScript**. - * Servidor Docker baseado em **Nginx** (configurado para rodar "lindamente" com Vue-router). - * Construção multi-estágio Docker, então você não precisa salvar ou _commitar_ código compilado. - * Testes _frontend_ rodados na hora da construção (pode ser desabilitado também). - * Feito tão modular quanto possível, então ele funciona fora da caixa, mas você pode gerar novamente com Vue CLI ou criar conforme você queira, e reutilizar o que quiser. -* **PGAdmin** para banco de dados PostgreSQL, você pode modificar para usar PHPMyAdmin e MySQL facilmente. -* **Flower** para monitoração de tarefas Celery. -* Balanceamento de carga entre _frontend_ e _backend_ com **Traefik**, então você pode ter ambos sob o mesmo domínio, separados por rota, mas servidos por diferentes containers. -* Integração Traefik, incluindo geração automática de certificados **HTTPS** Let's Encrypt. -* GitLab **CI** (integração contínua), incluindo testes _frontend_ e _backend_. - -## Full Stack FastAPI Couchbase - -GitHub: https://github.com/tiangolo/full-stack-fastapi-couchbase - -⚠️ **WARNING** ⚠️ - -Se você está iniciando um novo projeto do zero, verifique as alternativas aqui. - -Por exemplo, o gerador de projetos Full Stack FastAPI PostgreSQL pode ser uma alternativa melhor, como ele é ativamente mantido e utilizado. E ele inclui todos os novos recursos e melhorias. - -Você ainda é livre para utilizar o gerador baseado em Couchbase se quiser, ele provavelmente ainda funciona bem, e você já tem um projeto gerado com ele que roda bem também (e você provavelmente já atualizou ele para encaixar nas suas necessidades). - -Você pode ler mais sobre nas documentaçãoes do repositório. - -## Full Stack FastAPI MongoDB - -...pode demorar, dependendo do meu tempo disponível e outros fatores. 😅 🎉 - -## Modelos de Aprendizado de Máquina com spaCy e FastAPI - -GitHub: https://github.com/microsoft/cookiecutter-spacy-fastapi - -### Modelos de Aprendizado de Máquina com spaCy e FastAPI - Recursos - -* Integração com modelo NER **spaCy**. -* Formato de requisição **Busca Cognitiva Azure** acoplado. -* Servidor Python _web_ **Pronto para Produção** usando Uvicorn e Gunicorn. -* Implantação **Azure DevOps** Kubernetes (AKS) CI/CD acoplada. -* **Multilingual** facilmente escolhido como uma das linguagens spaCy acopladas durante a configuração do projeto. -* **Facilmente extensível** para outros modelos de _frameworks_ (Pytorch, Tensorflow), não apenas spaCy. +# Full Stack FastAPI Template + +_Templates_, embora tipicamente venham com alguma configuração específica, são desenhados para serem flexíveis e customizáveis. Isso permite que você os modifique e adapte para as especificações do seu projeto, fazendo-os um excelente ponto de partida. 🏁 + +Você pode usar esse _template_ para começar, já que ele inclui várias configurações iniciais, segurança, banco de dados, e alguns _endpoints_ de API já feitos para você. + +Repositório GitHub: Full Stack FastAPI Template + +## Full Stack FastAPI Template - Pilha de Tecnologias e Recursos + +- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) para a API do backend em Python. + - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) para as interações do Python com bancos de dados SQL (ORM). + - 🔍 [Pydantic](https://docs.pydantic.dev), usado pelo FastAPI, para validação de dados e gerenciamento de configurações. + - 💾 [PostgreSQL](https://www.postgresql.org) como banco de dados SQL. +- 🚀 [React](https://react.dev) para o frontend. + - 💃 Usando TypeScript, hooks, [Vite](https://vitejs.dev), e outras partes de uma _stack_ frontend moderna. + - 🎨 [Chakra UI](https://chakra-ui.com) para os componentes de frontend. + - 🤖 Um cliente frontend automaticamente gerado. + - 🧪 [Playwright](https://playwright.dev) para testes Ponta-a-Ponta. + - 🦇 Suporte para modo escuro. +- 🐋 [Docker Compose](https://www.docker.com) para desenvolvimento e produção. +- 🔒 _Hash_ seguro de senhas por padrão. +- 🔑 Autenticação por token JWT. +- 📫 Recuperação de senhas baseada em email. +- ✅ Testes com [Pytest](https://pytest.org). +- 📞 [Traefik](https://traefik.io) como proxy reverso / balanceador de carga. +- 🚢 Instruções de _deployment_ usando Docker Compose, incluindo como configurar um proxy frontend com Traefik para gerenciar automaticamente certificados HTTPS. +- 🏭 CI (Integração Contínua) e CD (_Deploy_ Contínuo) baseado em GitHub Actions. diff --git a/docs/ru/docs/advanced/additional-status-codes.md b/docs/ru/docs/advanced/additional-status-codes.md new file mode 100644 index 000000000..aab1f8ee3 --- /dev/null +++ b/docs/ru/docs/advanced/additional-status-codes.md @@ -0,0 +1,41 @@ +# Дополнительные статус коды + +По умолчанию **FastAPI** возвращает ответы, используя `JSONResponse`, помещая содержимое, которое вы возвращаете из вашей *операции пути*, внутрь этого `JSONResponse`. + +Он будет использовать код статуса по умолчанию или тот, который вы укажете в вашей *операции пути*. + +## Дополнительные статус коды + +Если вы хотите возвращать дополнительный статус код помимо основного, вы можете сделать это, возвращая объект `Response` напрямую, как `JSONResponse`, и устанавливая нужный статус код напрямую. + +Например, скажем, вы хотите создать *операцию пути*, которая позволяет обновлять элементы и возвращает HTTP-код 200 "OK" при успешном выполнении. + +Но вы также хотите, чтобы она принимала новые элементы. И если элемент ранее не существовал, он создаётся, и возвращался HTTP-код 201 "Created". + +Чтобы реализовать это, импортируйте `JSONResponse` и возвращайте ваш контент напрямую, устанавливая нужный `status_code`: + +{* ../../docs_src/additional_status_codes/tutorial001_an_py310.py hl[4,25] *} + +/// warning | Внимание + +Когда вы возвращаете объект `Response` напрямую, как в примере выше, он будет возвращён как есть. + +Он не будет сериализован при помощи модели и т.д. + +Убедитесь, что в нём содержатся именно те данные, которые вы хотите, и что значения являются валидным JSON (если вы используете `JSONResponse`). + +/// + +/// note | Технические детали + +Вы также можете использовать `from starlette.responses import JSONResponse`. + +**FastAPI** предоставляет тот же `starlette.responses` через `fastapi.responses` просто для вашего удобства, как разработчика. Но большинство доступных Response-классов поступают напрямую из Starlette. То же самое касается и `status`. + +/// + +## OpenAPI и документация API + +Если вы возвращаете дополнительные коды статусов и ответы напрямую, они не будут включены в схему OpenAPI (документацию API), потому что FastAPI не может заранее знать, что вы собираетесь вернуть. + +Но вы можете задокументировать это в вашем коде, используя: [Дополнительные ответы в OpenAPI](additional-responses.md){.internal-link target=_blank}. diff --git a/docs/ru/docs/advanced/index.md b/docs/ru/docs/advanced/index.md new file mode 100644 index 000000000..b5cb733e7 --- /dev/null +++ b/docs/ru/docs/advanced/index.md @@ -0,0 +1,21 @@ +# Расширенное руководство пользователя + +## Дополнительные возможности + +Основное [Учебник - Руководство пользователя](../tutorial/index.md){.internal-link target=_blank} должно быть достаточно, чтобы познакомить вас со всеми основными функциями **FastAPI**. + +В следующих разделах вы увидите другие варианты, конфигурации и дополнительные возможности. + +/// tip + +Следующие разделы **не обязательно являются "продвинутыми"**. + +И вполне возможно, что для вашего случая использования решение находится в одном из них. + +/// + +## Сначала прочитайте Учебник - Руководство пользователя + +Вы все еще можете использовать большинство функций **FastAPI** со знаниями из [Учебник - Руководство пользователя](../tutorial/index.md){.internal-link target=_blank}. + +И следующие разделы предполагают, что вы уже прочитали его, и предполагают, что вы знаете эти основные идеи. diff --git a/docs/ru/docs/advanced/response-change-status-code.md b/docs/ru/docs/advanced/response-change-status-code.md new file mode 100644 index 000000000..37dade99f --- /dev/null +++ b/docs/ru/docs/advanced/response-change-status-code.md @@ -0,0 +1,31 @@ +# Response - Изменение cтатус кода + +Вы, вероятно, уже читали о том, что можно установить [Состояние ответа по умолчанию](../tutorial/response-status-code.md){.internal-link target=_blank}. + +Но в некоторых случаях вам нужно вернуть код состояния, отличный от установленного по умолчанию. + +## Пример использования + +Например, представьте, что вы хотите возвращать HTTP код состояния "OK" `200` по умолчанию. + +Но если данные не существовали, вы хотите создать их и вернуть HTTP код состояния "CREATED" `201`. + +При этом вы всё ещё хотите иметь возможность фильтровать и преобразовывать возвращаемые данные с помощью `response_model`. + +Для таких случаев вы можете использовать параметр `Response`. + +## Использование параметра `Response` + +Вы можете объявить параметр типа `Response` в вашей *функции обработки пути* (так же как для cookies и headers). + +И затем вы можете установить `status_code` в этом *временном* объекте ответа. + +{* ../../docs_src/response_change_status_code/tutorial001.py hl[1,9,12] *} + +После этого вы можете вернуть любой объект, который вам нужен, как обычно (`dict`, модель базы данных и т.д.). + +И если вы объявили `response_model`, он всё равно будет использоваться для фильтрации и преобразования возвращаемого объекта. + +**FastAPI** будет использовать этот *временный* ответ для извлечения кода состояния (а также cookies и headers) и поместит их в финальный ответ, который содержит возвращаемое вами значение, отфильтрованное любым `response_model`. + +Вы также можете объявить параметр `Response` в зависимостях и установить код состояния в них. Но помните, что последнее установленное значение будет иметь приоритет. diff --git a/docs/ru/docs/advanced/response-directly.md b/docs/ru/docs/advanced/response-directly.md new file mode 100644 index 000000000..ee83d22b1 --- /dev/null +++ b/docs/ru/docs/advanced/response-directly.md @@ -0,0 +1,65 @@ +# Возврат ответа напрямую + +Когда вы создаёте **FastAPI** *операцию пути*, вы можете возвращать из неё любые данные: `dict`, `list`, Pydantic-модель, модель базы данных и т.д. + +По умолчанию **FastAPI** автоматически преобразует возвращаемое значение в JSON с помощью `jsonable_encoder`, как описано в [JSON кодировщик](../tutorial/encoder.md){.internal-link target=_blank}. + +Затем "под капотом" эти данные, совместимые с JSON (например `dict`), помещаются в `JSONResponse`, который используется для отправки ответа клиенту. + +Но вы можете возвращать `JSONResponse` напрямую из ваших *операций пути*. + +Это может быть полезно, например, если нужно вернуть пользовательские заголовки или куки. + +## Возврат `Response` + +На самом деле, вы можете возвращать любой объект `Response` или его подкласс. + +/// tip | Подсказка + +`JSONResponse` сам по себе является подклассом `Response`. + +/// + +И когда вы возвращаете `Response`, **FastAPI** передаст его напрямую. + +Это не приведет к преобразованию данных с помощью Pydantic-моделей, содержимое не будет преобразовано в какой-либо тип и т.д. + +Это даёт вам большую гибкость. Вы можете возвращать любые типы данных, переопределять любые объявления или валидацию данных и т.д. + +## Использование `jsonable_encoder` в `Response` + +Поскольку **FastAPI** не изменяет объект `Response`, который вы возвращаете, вы должны убедиться, что его содержимое готово к отправке. + +Например, вы не можете поместить Pydantic-модель в `JSONResponse`, не преобразовав её сначала в `dict` с помощью преобразования всех типов данных (таких как `datetime`, `UUID` и т.д.) в совместимые с JSON типы. + +В таких случаях вы можете использовать `jsonable_encoder` для преобразования данных перед передачей их в ответ: + +{* ../../docs_src/response_directly/tutorial001.py hl[6:7,21:22] *} + +/// note | Технические детали + +Вы также можете использовать `from starlette.responses import JSONResponse`. + +**FastAPI** предоставляет `starlette.responses` через `fastapi.responses` просто для вашего удобства, как разработчика. Но большинство доступных Response-классов поступают напрямую из Starlette. + +/// + +## Возврат пользовательского `Response` + +Пример выше показывает все необходимые части, но он пока не очень полезен, так как вы могли бы просто вернуть `item` напрямую, и **FastAPI** поместил бы его в `JSONResponse`, преобразовав в `dict` и т.д. Всё это происходит по умолчанию. + +Теперь давайте посмотрим, как можно использовать это для возврата пользовательского ответа. + +Допустим, вы хотите вернуть ответ в формате XML. + +Вы можете поместить ваш XML-контент в строку, поместить её в `Response` и вернуть: + +{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *} + +## Примечания + +Когда вы возвращаете объект `Response` напрямую, его данные не валидируются, не преобразуются (не сериализуются) и не документируются автоматически. + +Но вы всё равно можете задокументировать это, как описано в [Дополнительные ответы в OpenAPI](additional-responses.md){.internal-link target=_blank}. + +В следующих разделах вы увидите, как использовать/объявлять такие кастомные `Response`, при этом сохраняя автоматическое преобразование данных, документацию и т.д. diff --git a/docs/uk/docs/tutorial/body-updates.md b/docs/uk/docs/tutorial/body-updates.md new file mode 100644 index 000000000..e78b5a5bf --- /dev/null +++ b/docs/uk/docs/tutorial/body-updates.md @@ -0,0 +1,116 @@ +# Тіло – Оновлення + +## Оновлення з використанням `PUT` + +Щоб оновити елемент, Ви можете використати HTTP `PUT` операцію. + +Ви можете використати `jsonable_encoder`, щоб перетворити вхідні дані на такі, які можна зберігати як JSON (наприклад, у NoSQL базі даних). Наприклад, перетворюючи `datetime` у `str`. + +{* ../../docs_src/body_updates/tutorial001_py310.py hl[28:33] *} + +`PUT` використовується для отримання даних, які мають замінити чинні дані. + +### Попередження про заміну + +Це означає, що якщо Ви хочете оновити елемент `bar`, використовуючи `PUT` з тілом: + +```Python +{ + "name": "Barz", + "price": 3, + "description": None, +} +``` + +оскільки він не містить вже збереженого атрибута `"tax": 20.2`, модель введення прийме значення за замовчуванням `"tax": 10.5`. + +І дані будуть збережені з цим "новим" значенням `tax` = `10.5`. + +## Часткові оновлення з `PATCH` + +Ви також можете використовувати операцію HTTP `PATCH` для *часткового* оновлення даних. + +Це означає, що Ви можете надіслати лише ті дані, які хочете оновити, залишаючи інші без змін. + +/// note | Примітка + +`PATCH` менш відомий і рідше використовується, ніж `PUT`. + +І багато команд використовують лише `PUT`, навіть для часткових оновлень. + +Ви **вільні** використовувати їх так, як хочете, **FastAPI** не накладає обмежень. + +Але цей посібник показує Вам більш-менш як їх задумано використовувати. + +/// + +### Використання параметра `exclude_unset` у Pydantic + +Якщо Ви хочете отримати часткові оновлення, дуже зручно використовувати параметр `exclude_unset` у методі `.model_dump()` моделі Pydantic. + +Наприклад: `item.model_dump(exclude_unset=True)`. + +/// info | Інформація + +У Pydantic v1 цей метод називався `.dict()`, він був застарілий (але все ще підтримується) у Pydantic v2, і був перейменований у `.model_dump()`. + +Приклади тут використовують `.dict()` для сумісності з Pydantic v1, але Вам слід використовувати `.model_dump()`, якщо можете використовувати Pydantic v2. + +/// + +Це створить `dict` лише з тими даними, які були явно встановлені під час створення моделі `item`, виключаючи значення за замовчуванням. + +Тоді Ви можете використовувати це, щоб створити `dict` лише з даними, які були встановлені (надіслані у запиті), пропускаючи значення за замовчуванням: + +{* ../../docs_src/body_updates/tutorial002_py310.py hl[32] *} + +### Використання параметра `update` у Pydantic + +Тепер Ви можете створити копію наявної моделі за допомогою `.model_copy()`, і передати параметр `update` з `dict` , який містить дані для оновлення. + +/// info | Інформація + +У Pydantic v1 метод називався `.copy()`, він був застарілий (але все ще підтримується) у Pydantic v2, і був перейменований у `.model_copy()`. + +Приклади тут використовують `.copy()` для сумісності з Pydantic v1, але якщо Ви можете використовувати Pydantic v2 — Вам слід використовувати `.model_copy()` замість цього. + +/// + +Наприклад: `stored_item_model.model_copy(update=update_data)`: + +{* ../../docs_src/body_updates/tutorial002_py310.py hl[33] *} + +### Підсумок часткових оновлень + +У підсумку, щоб застосувати часткові оновлення, Ви: + +* (Опціонально) використовуєте `PATCH` замість `PUT`. +* Отримуєте збережені дані. +* Поміщаєте ці дані в модель Pydantic. +* Генеруєте `dict` без значень за замовчуванням з моделі введення (використовуючи `exclude_unset`). + * Таким чином Ви оновите лише ті значення, які були явно задані користувачем, замість того, щоб перезаписувати вже збережені значення значеннями за замовчуванням з вашої моделі. +* Створюєте копію збереженої моделі, оновлюючи її атрибути отриманими частковими оновленнями (використовуючи параметр `update`). +* Перетворюєте скопійовану модель на щось, що можна зберегти у вашу БД (наприклад, використовуючи `jsonable_encoder`). + * Це можна порівняти з повторним використанням методу `.model_dump()` моделі, але це гарантує (і перетворює) значення у типи даних, які можна перетворити на JSON, наприклад, `datetime` на `str`. +* Зберігаєте дані у вашу БД. +* Повертаєте оновлену модель. + +{* ../../docs_src/body_updates/tutorial002_py310.py hl[28:35] *} + +/// tip | Порада + +Насправді Ви можете використовувати цю саму техніку і з операцією HTTP `PUT`. + +Але приклад тут використовує `PATCH`, тому що він був створений саме для таких випадків. + +/// + +/// note | Примітка + +Зверніть увагу, що модель запиту все ще проходить валідацію. + +Тож, якщо Ви хочете отримувати часткові оновлення, які можуть не містити жодного атрибута, Вам потрібно мати модель, де всі атрибути позначені як необов’язкові (зі значеннями за замовчуванням або `None`). + +Щоб розрізняти моделі з усіма необов’язковими значеннями для **оновлення** і моделі з обов’язковими значеннями для **створення**, Ви можете скористатись ідеями, описаними у [Додаткові моделі](extra-models.md){.internal-link target=_blank}. + +/// diff --git a/docs/uk/docs/tutorial/response-model.md b/docs/uk/docs/tutorial/response-model.md new file mode 100644 index 000000000..def1f8a2d --- /dev/null +++ b/docs/uk/docs/tutorial/response-model.md @@ -0,0 +1,358 @@ +# Модель відповіді — Тип, що повертається + +Ви можете оголосити тип, який використовуватиметься у відповіді, за допомогою *анотації типу, що повертається* *функцією операцією шляху* (path operation) + +**Анотацію типу** можна вказати так само як і для вхідних **параметрів** функції: це можуть бути моделі Pydantic, списки (lists), словники (dictionaries), скалярні значення, як-от цілі числа (integers), булеві значення (booleans) тощо. + +{* ../../docs_src/response_model/tutorial001_01_py310.py hl[16,21] *} + +FastAPI використовуватиме цей тип, щоб: + +* **Перевірити правильність** повернених даних. + * Якщо дані не валідні (наприклад, відсутнє поле), це означає, що Ваш код додатку працює некоректно і не повертає те, що повинен. У такому випадку FastAPI поверне помилку сервера, замість того щоб віддати недопустимі дані. Так Ви та Ваші клієнти будете впевнені, що отримуєте очікувані дані у правильному форматі. + +* Додати **JSON Schema** відповіді до специфікації OpenAPI в *операціях шляху*. + * Це буде використано в **автоматичній документації**. + * А також інструментами, які автоматично генерують клієнтський код. + +Але найголовніше: + +* FastAPI **обмежить та відфільтрує** вихідні дані відповідно до типу, вказаного у відповіді. + * Це особливо важливо для **безпеки**. Деталі нижче. + +## Параметр `response_model` + +Іноді Вам потрібно або зручно повертати інші типи даних, ніж ті, що зазначені як тип відповіді. + +Наприклад, Ви можете **повертати словник** або об’єкт бази даних, але **оголосити модель Pydantic** як модель відповіді. Тоді модель Pydantic автоматично оброблятиме валідацію, документацію тощо. + +Якщо Ви додасте анотацію типу для повернення, редактор коду або mypy можуть поскаржитися, що функція повертає інший тип (наприклад, dict замість Item). + +У таких випадках можна скористатися параметром `response_model` в декораторі маршруту (наприклад, @app.get()). + +Параметр `response_model` працює з будь-яким *оператором шляху*: + +* `@app.get()` +* `@app.post()` +* `@app.put()` +* `@app.delete()` +* тощо. + +{* ../../docs_src/response_model/tutorial001_py310.py hl[17,22,24:27] *} + +/// note | Примітка + +Зверніть увагу, що `response_model` є параметром методу-декоратора (`get`, `post`, тощо), а не *функцією операцією шляху* (path operation function), як це робиться з параметрами або тілом запиту. + +/// + +`response_model` приймає такий самий тип, який Ви б вказали для поля моделі Pydantic. Тобто це може бути як Pydantic-модель, так і, наприклад, `list` із моделей Pydantic — `List[Item]`. + +FastAPI використовуватиме `response_model` для створення документації, валідації даних та — найважливіше — **перетворення та фільтрації вихідних даних** згідно з оголошеним типом. + +/// tip | Порада + +Якщо у Вас увімкнено сувору перевірку типів у редакторі, mypy тощо, Ви можете оголосити тип повернення функції як `Any`. + +Таким чином, Ви повідомляєте редактору, що свідомо повертаєте будь-що. Але FastAPI усе одно виконуватиме створення документації, валідацію, фільтрацію тощо за допомогою параметра `response_model`. + +/// + +### Пріоритет `response_model` + +Якщо Ви вказуєте і тип повернення, і `response_model`, то FastAPI використовуватиме `response_model` з пріоритетом. + +Таким чином, Ви можете додати правильні анотації типів до ваших функцій, навіть якщо вони повертають тип, відмінний від `response_model`. Це буде корисно для редакторів коду та інструментів, таких як mypy. І при цьому FastAPI продовжить виконувати валідацію даних, генерувати документацію тощо на основі `response_model`. + +Ви також можете використати `response_model=None`, щоб вимкнути створення моделі відповіді для цієї *операції шляху*. Це може знадобитися, якщо Ви додаєте анотації типів до об'єктів, які не є допустимими полями Pydantic — приклад цього Ви побачите в одному з наступних розділів. + +## Повернути ті самі вхідні дані + +Тут ми оголошуємо модель `UserIn`, яка містить звичайний текстовий пароль: + +{* ../../docs_src/response_model/tutorial002_py310.py hl[7,9] *} + +/// info | Інформація + +Щоб використовувати `EmailStr`, спочатку встановіть `email-validator`. + +Переконайтесь, що Ви створили [віртуальне середовище](../virtual-environments.md){.internal-link target=_blank}, активували його, а потім встановили пакет, наприклад: + +```console +$ pip install email-validator +``` + +or with: + +```console +$ pip install "pydantic[email]" +``` + +/// + +І ми використовуємо цю модель, щоб оголосити і вхідні, і вихідні дані: + +{* ../../docs_src/response_model/tutorial002_py310.py hl[16] *} + +Тепер, коли браузер створює користувача з паролем, API поверне той самий пароль у відповіді. + +У цьому випадку це може не бути проблемою, адже саме користувач надіслав пароль. + +Але якщо ми використаємо цю ж модель для іншої операції шляху, ми можемо випадково надіслати паролі наших користувачів кожному клієнту. + +/// danger | Обережно + +Ніколи не зберігайте пароль користувача у відкритому вигляді та не надсилайте його у відповіді, якщо тільки Ви не знаєте всі ризики і точно розумієте, що робите. + +/// + +## Додайте окрему вихідну модель + +Замість цього ми можемо створити вхідну модель з відкритим паролем і вихідну модель без нього: + +{* ../../docs_src/response_model/tutorial003_py310.py hl[9,11,16] *} + +Тут, навіть якщо *функція операції шляху* повертає об'єкт користувача, який містить пароль: + +{* ../../docs_src/response_model/tutorial003_py310.py hl[24] *} + +...ми оголосили `response_model` як нашу модель `UserOut`, яка не містить пароля: + +{* ../../docs_src/response_model/tutorial003_py310.py hl[22] *} + +Таким чином, **FastAPI** автоматично відфільтрує всі дані, які не вказані у вихідній моделі (за допомогою Pydantic). + +### `response_model` або тип повернення + +У цьому випадку, оскільки дві моделі різні, якщо ми анотуємо тип повернення функції як `UserOut`, редактор і такі інструменти, як mypy, видадуть помилку, бо фактично ми повертаємо інший тип. + +Тому в цьому прикладі ми використовуємо параметр `response_model`, а не анотацію типу повернення. + +...але читайте далі, щоб дізнатися, як обійти це обмеження. + +## Тип повернення і фільтрація даних + +Продовжимо з попереднього прикладу. Ми хотіли **анотувати функцію одним типом**, але при цьому повертати з неї більше даних. + +Ми хочемо, щоб FastAPI продовжував **фільтрувати** ці дані за допомогою response_model. Тобто навіть якщо функція повертає більше інформації, у відповіді будуть лише ті поля, які вказані у response_model. + +У попередньому прикладі, оскільки класи були різні, нам довелося використовувати параметр `response_model`. Але це означає, що ми не отримуємо підтримки з боку редактора коду та інструментів перевірки типів щодо типу, який повертає функція. + +Проте в більшості випадків, коли нам потрібно зробити щось подібне, ми просто хочемо, щоб модель **відфільтрувала або прибрала** частину даних, як у цьому прикладі. + +У таких випадках ми можемо використати класи та спадкування, щоб скористатися **анотаціями типів** функцій — це дає кращу підтримку з боку редактора та інструментів типу mypy, і при цьому FastAPI продовжує виконувати **фільтрацію даних** у відповіді. + +{* ../../docs_src/response_model/tutorial003_01_py310.py hl[7:10,13:14,18] *} + +Завдяки цьому ми отримуємо підтримку інструментів — від редакторів і mypy, оскільки цей код є коректним з точки зору типів, — але ми також отримуємо фільтрацію даних від FastAPI. + +Як це працює? Давайте розберемося. 🤓 + +### Типи та підтримка інструментів + +Спершу подивимось, як це бачать редактори, mypy та інші інструменти. + +`BaseUser` має базові поля. Потім `UserIn` успадковує `BaseUser` і додає поле `password`, отже, він матиме всі поля з обох моделей. + +Ми зазначаємо тип повернення функції як `BaseUser`, але фактично повертаємо екземпляр `UserIn`. + +Редактор, mypy та інші інструменти не скаржитимуться на це, тому що з точки зору типізації `UserIn` є підкласом `BaseUser`, а це означає, що він є `валідним` типом, коли очікується будь-що, що є `BaseUser`. + +### Фільтрація даних у FastAPI + +Тепер для FastAPI він бачить тип повернення і переконується, що те, що Ви повертаєте, містить **тільки** поля, які оголошені у цьому типі. + +FastAPI виконує кілька внутрішніх операцій з Pydantic, щоб гарантувати, що правила наслідування класів не застосовуються для фільтрації повернених даних, інакше Ви могли б повернути значно більше даних, ніж очікували. + +Таким чином, Ви отримуєте найкраще з двох світів: анотації типів **з підтримкою інструментів** і **фільтрацію даних**. + +## Подивитись у документації + +Коли Ви дивитесь автоматичну документацію, Ви можете побачити, що вхідна модель і вихідна модель мають власну JSON-схему: + + + +І обидві моделі використовуються для інтерактивної API-документації: + + + +## Інші анотації типів повернення + +Існують випадки, коли Ви повертаєте щось, що не є допустимим полем Pydantic, але анотуєте це у функції лише для того, щоб отримати підтримку від інструментів (редактора, mypy тощо). + +### Повернення Response напряму + +Найпоширенішим випадком буде [повернення Response напряму, як пояснюється пізніше у розширеній документації](../advanced/response-directly.md){.internal-link target=_blank}. + +{* ../../docs_src/response_model/tutorial003_02.py hl[8,10:11] *} + +Цей простий випадок автоматично обробляється FastAPI, тому що анотація типу повернення — це клас (або підклас) `Response`. + +І інструменти також будуть задоволені, бо і `RedirectResponse`, і `JSONResponse` є підкласами `Response`, отже анотація типу коректна. + +### Анотація підкласу Response + +Також можна використовувати підклас `Response` у анотації типу: + +{* ../../docs_src/response_model/tutorial003_03.py hl[8:9] *} + +Це теж працюватиме, бо `RedirectResponse` — підклас `Response`, і FastAPI автоматично обробить цей простий випадок. + +### Некоректні анотації типу повернення + +Але коли Ви повертаєте якийсь інший довільний об’єкт, що не є валідним типом Pydantic (наприклад, об’єкт бази даних), і анотуєте його так у функції, FastAPI спробує створити Pydantic модель відповіді на основі цієї анотації типу, і це завершиться помилкою. + +Те саме станеться, якщо Ви використовуєте union між різними типами, де один або більше не є валідними типами Pydantic, наприклад, це спричинить помилку 💥: + +{* ../../docs_src/response_model/tutorial003_04_py310.py hl[8] *} + +...це не працює, тому що тип анотації не є типом Pydantic і не є просто класом `Response` або його підкласом, а є об’єднанням (union) — або `Response`, або `dict`. + +### Відключення Моделі Відповіді + +Продовжуючи приклад вище, можливо, Ви не хочете використовувати стандартну валідацію даних, автоматичну документацію, фільтрацію тощо, які FastAPI виконує за замовчуванням. + +Але ви все одно можете залишити анотацію типу у функції, щоб зберегти підтримку з боку інструментів, таких як редактори коду або статичні перевірки типів (наприклад, mypy). + +У такому випадку ви можете вимкнути генерацію моделі відповіді, встановивши `response_model=None`: + +{* ../../docs_src/response_model/tutorial003_05_py310.py hl[7] *} + +Це змусить FastAPI пропустити генерацію моделі відповіді, і таким чином Ви зможете використовувати будь-які анотації типів повернення без впливу на вашу FastAPI аплікацію. 🤓 + +## Параметри кодування моделі відповіді + +Ваша модель відповіді може мати значення за замовчуванням, наприклад: + +{* ../../docs_src/response_model/tutorial004_py310.py hl[9,11:12] *} + +* `description: Union[str, None] = None` (або `str | None = None` у Python 3.10) має значення за замовчуванням `None`. +* `tax: float = 10.5` має значення за замовчуванням `10.5`. +* `tags: List[str] = []` має значення за замовчуванням порожній список: `[]`. + +Але Ви можете захотіти не включати їх у результат, якщо вони фактично не були збережені. + +Наприклад, якщо у Вас є моделі з багатьма необов’язковими атрибутами у NoSQL базі даних, але Ви не хочете відправляти дуже довгі JSON-відповіді, повні значень за замовчуванням. + +### Використовуйте параметр `response_model_exclude_unset` + +Ви можете встановити параметр декоратора шляху `response_model_exclude_unset=True`: + +{* ../../docs_src/response_model/tutorial004_py310.py hl[22] *} + +і ці значення за замовчуванням не будуть включені у відповідь, тільки фактично встановлені значення. + +Отже, якщо Ви надішлете запит до цього оператора шляху для елемента з item_id `foo`, відповідь (без включення значень за замовчуванням) буде: + +```JSON +{ + "name": "Foo", + "price": 50.2 +} +``` + +/// info | Інформація + +У Pydantic версії 1 метод називався `.dict()`, він був застарілий (але ще підтримується) у Pydantic версії 2 і перейменований у `.model_dump()`. + +Приклади тут використовують `.dict()` для сумісності з Pydantic v1, але Вам слід використовувати `.model_dump()`, якщо Ви можете використовувати Pydantic v2. + +/// + +/// info | Інформація + +FastAPI використовує `.dict()` моделі Pydantic з параметром `exclude_unset`, щоб досягти цього. + +/// + +/// info | Інформація + +Ви також можете використовувати: + +* `response_model_exclude_defaults=True` +* `response_model_exclude_none=True` + +як описано в документації Pydantic for `exclude_defaults` та `exclude_none`. + +/// + +#### Дані зі значеннями для полів із типовими значеннями + +Але якщо Ваші дані мають значення для полів моделі з типовими значеннями, як у елемента з item_id `bar`: + +```Python hl_lines="3 5" +{ + "name": "Bar", + "description": "The bartenders", + "price": 62, + "tax": 20.2 +} +``` +вони будуть включені у відповідь. + +#### Дані з тими самими значеннями, що й типові + +Якщо дані мають ті самі значення, що й типові, як у елемента з item_id `baz`: + +```Python hl_lines="3 5-6" +{ + "name": "Baz", + "description": None, + "price": 50.2, + "tax": 10.5, + "tags": [] +} +``` + +FastAPI достатньо розумний (насправді, Pydantic достатньо розумний), щоб зрозуміти, що, хоча `description`, `tax` і `tags` мають ті самі значення, що й типові, вони були встановлені явно (а не взяті як значення за замовчуванням). + +Отже, вони будуть включені у JSON-відповідь. + +/// tip | Порада + +Зверніть увагу, що типові значення можуть бути будь-якими, не лише `None`. + +Це може бути list (`[]`), `float` 10.5 тощо. + +/// + +### `response_model_include` та `response_model_exclude` + +Ви також можете використовувати параметри *декоратора операції шляху* `response_model_include` та `response_model_exclude`. + +Вони приймають `set` (множину) рядків (`str`) з іменами атрибутів, які потрібно включити (пропускаючи інші) або виключити (включаючи інші). + +Це можна використовувати як швидкий спосіб, якщо у Вас є лише одна модель Pydantic і Ви хочете видалити деякі дані з виводу. + +/// tip | Порада + +Але все ж рекомендується використовувати описані вище підходи, із застосуванням кількох класів, замість цих параметрів. + + +Це тому, що JSON Schema, який генерується у вашому OpenAPI додатку (і в документації), все одно буде відповідати повній моделі, навіть якщо Ви використовуєте `response_model_include` або `response_model_exclude` для виключення деяких атрибутів. + +Це також стосується `response_model_by_alias`, який працює подібним чином. + +/// + +{* ../../docs_src/response_model/tutorial005_py310.py hl[29,35] *} + +/// tip | Порада + +Синтаксис `{"name", "description"}` створює `set` з цими двома значеннями. + +Він еквівалентний `set(["name", "description"])`. + +/// + +#### Використання `list` замість `set` + +Якщо Ви забудете використати `set` і натомість застосуєте `list` або `tuple`, FastAPI все одно перетворить це на `set`, і все працюватиме правильно: + +{* ../../docs_src/response_model/tutorial006_py310.py hl[29,35] *} + +## Підсумок + +Використовуйте параметр `response_model` *декоратора операції шляху*, щоб визначати моделі відповіді, особливо щоб гарантувати фільтрацію приватних даних. + +Використовуйте `response_model_exclude_unset`, щоб повертати лише явно встановлені значення. diff --git a/docs/uk/docs/tutorial/security/index.md b/docs/uk/docs/tutorial/security/index.md new file mode 100644 index 000000000..c3d94be8d --- /dev/null +++ b/docs/uk/docs/tutorial/security/index.md @@ -0,0 +1,104 @@ +# Безпека + +Існує багато способів реалізувати безпеку, автентифікацію та авторизацію. + +Це зазвичай складна і "непроста" тема. + +У багатьох фреймворках і системах забезпечення безпеки та автентифікації займає величезну частину зусиль і коду (іноді — понад 50% всього написаного коду). + +**FastAPI** надає кілька інструментів, які допоможуть Вам впоратися з **безпекою** легко, швидко, стандартним способом, без необхідності вивчати всі специфікації безпеки. + +Але спочатку — кілька коротких понять. + +## Поспішаєте? + +Якщо Вам не цікаві всі ці терміни й просто потрібно *швидко* додати автентифікацію за логіном і паролем — переходьте до наступних розділів. + +## OAuth2 + +OAuth2 — це специфікація, що описує кілька способів обробки автентифікації та авторизації. + +Це досить об'ємна специфікація, яка охоплює складні випадки використання. + +Вона включає способи автентифікації через "третю сторону". + +Саме це лежить в основі "входу через Google, Facebook, X (Twitter), GitHub" тощо. + +### OAuth 1 + +Раніше існував OAuth 1, який значно відрізняється від OAuth2 і є складнішим, оскільки містив специфікації для шифрування комунікацій. + +Зараз майже не використовується. + +OAuth2 не вказує, як саме шифрувати з'єднання — воно очікує, що ваш застосунок працює через HTTPS. + +/// tip | Порада + +У розділі про **деплой** Ви побачите, як налаштувати HTTPS безкоштовно з Traefik та Let's Encrypt. + +/// + +## OpenID Connect + +OpenID Connect — ще одна специфікація, побудована на основі **OAuth2**. + +Вона розширює OAuth2, уточнюючи деякі неоднозначності для досягнення кращої сумісності. + +Наприклад, вхід через Google використовує OpenID Connect (який базується на OAuth2). + +Але вхід через Facebook — ні. Він має власну реалізацію на базі OAuth2. + +### OpenID (не "OpenID Connect") + +Існувала також специфікація "OpenID", яка намагалася розвʼязати ті самі задачі, що й **OpenID Connect**, але не базувалась на OAuth2. + +Це була зовсім інша система, і сьогодні вона майже не використовується. + +## OpenAPI + +OpenAPI (раніше Swagger) — це специфікація для побудови API (тепер під егідою Linux Foundation). + +**FastAPI** базується на **OpenAPI**. + +Завдяки цьому Ви отримуєте автоматичну інтерактивну документацію, генерацію коду та багато іншого. + +OpenAPI дозволяє описувати різні "схеми" безпеки. + +Використовуючи їх, Ви можете скористатися всіма цими інструментами, що базуються на стандартах, зокрема інтерактивними системами документації. + +OpenAPI визначає такі схеми безпеки: + +* `apiKey`: специфічний для застосунку ключ, який може передаватися через: + * Параметр запиту. + * Заголовок. + * Cookie. +* `http`: стандартні методи HTTP-автентифікації, включаючи: + * `bearer`: заголовок `Authorization` зі значенням `Bearer` та токеном. Це успадковано з OAuth2. + * HTTP Basic автентифікація + * HTTP Digest, тощо. +* `oauth2`: усі способи обробки безпеки за допомогою OAuth2 (так звані «потоки»). + * Деякі з цих потоків підходять для створення власного провайдера автентифікації OAuth 2.0 (наприклад, Google, Facebook, X (Twitter), GitHub тощо): + * `implicit`— неявний + * `clientCredentials`— облікові дані клієнта + * `authorizationCode` — код авторизації + * Але є один окремий «потік», який ідеально підходить для реалізації автентифікації всередині одного додатку: + * `password`: у наступних розділах буде приклад використання цього потоку. +* `openIdConnect`: дозволяє автоматично виявляти параметри автентифікації OAuth2. + * Це автоматичне виявлення визначається у специфікації OpenID Connect. + + +/// tip | Порада + +Інтеграція інших провайдерів автентифікації/авторизації, таких як Google, Facebook, X (Twitter), GitHub тощо — також можлива і відносно проста. + +Найскладніше — це створити власного провайдера автентифікації/авторизації, як Google чи Facebook. Але **FastAPI** надає Вам інструменти, щоб зробити це легко, беручи на себе важку частину роботи. + +/// + +## Інструменти **FastAPI** + +FastAPI надає кілька інструментів для кожної з описаних схем безпеки в модулі `fastapi.security`, які спрощують використання цих механізмів захисту. + +У наступних розділах Ви побачите, як додати безпеку до свого API за допомогою цих інструментів **FastAPI**. + +А також побачите, як вона автоматично інтегрується в інтерактивну документацію вашого API. diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 80eb783da..b02bf8b4f 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.115.12" +__version__ = "0.116.1" from starlette import status as status diff --git a/fastapi/_compat.py b/fastapi/_compat.py index c07e4a3b0..227ad837d 100644 --- a/fastapi/_compat.py +++ b/fastapi/_compat.py @@ -16,6 +16,7 @@ from typing import ( Tuple, Type, Union, + cast, ) from fastapi.exceptions import RequestErrorModel @@ -231,6 +232,10 @@ if PYDANTIC_V2: field_mapping, definitions = schema_generator.generate_definitions( inputs=inputs ) + for item_def in cast(Dict[str, Dict[str, Any]], definitions).values(): + if "description" in item_def: + item_description = cast(str, item_def["description"]).split("\f")[0] + item_def["description"] = item_description return field_mapping, definitions # type: ignore[return-value] def is_scalar_field(field: ModelField) -> bool: diff --git a/fastapi/applications.py b/fastapi/applications.py index 6d427cdc2..05c7bd2be 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -748,7 +748,7 @@ class FastAPI(Starlette): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -1720,7 +1720,7 @@ class FastAPI(Starlette): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -2093,7 +2093,7 @@ class FastAPI(Starlette): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -2471,7 +2471,7 @@ class FastAPI(Starlette): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -2849,7 +2849,7 @@ class FastAPI(Starlette): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -3222,7 +3222,7 @@ class FastAPI(Starlette): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -3595,7 +3595,7 @@ class FastAPI(Starlette): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -3968,7 +3968,7 @@ class FastAPI(Starlette): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -4346,7 +4346,7 @@ class FastAPI(Starlette): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -4425,7 +4425,7 @@ class FastAPI(Starlette): app = FastAPI() - @app.put("/items/{item_id}") + @app.trace("/items/{item_id}") def trace_item(item_id: str): return None ``` @@ -4515,14 +4515,17 @@ class FastAPI(Starlette): ```python import time + from typing import Awaitable, Callable - from fastapi import FastAPI, Request + from fastapi import FastAPI, Request, Response app = FastAPI() @app.middleware("http") - async def add_process_time_header(request: Request, call_next): + async def add_process_time_header( + request: Request, call_next: Callable[[Request], Awaitable[Response]] + ) -> Response: start_time = time.time() response = await call_next(request) process_time = time.time() - start_time diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index 852ecced6..3b0650251 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -819,6 +819,25 @@ def request_params_to_args( return values, errors +def is_union_of_base_models(field_type: Any) -> bool: + """Check if field type is a Union where all members are BaseModel subclasses.""" + from fastapi.types import UnionType + + origin = get_origin(field_type) + + # Check if it's a Union type (covers both typing.Union and types.UnionType in Python 3.10+) + if origin is not Union and origin is not UnionType: + return False + + union_args = get_args(field_type) + + for arg in union_args: + if not lenient_issubclass(arg, BaseModel): + return False + + return True + + def _should_embed_body_fields(fields: List[ModelField]) -> bool: if not fields: return False @@ -832,10 +851,12 @@ def _should_embed_body_fields(fields: List[ModelField]) -> bool: # If it explicitly specifies it is embedded, it has to be embedded if getattr(first_field.field_info, "embed", None): return True - # If it's a Form (or File) field, it has to be a BaseModel to be top level + # If it's a Form (or File) field, it has to be a BaseModel (or a union of BaseModels) to be top level # otherwise it has to be embedded, so that the key value pair can be extracted - if isinstance(first_field.field_info, params.Form) and not lenient_issubclass( - first_field.type_, BaseModel + if ( + isinstance(first_field.field_info, params.Form) + and not lenient_issubclass(first_field.type_, BaseModel) + and not is_union_of_base_models(first_field.type_) ): return True return False diff --git a/fastapi/routing.py b/fastapi/routing.py index 457481e32..54c75a027 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -9,6 +9,7 @@ from typing import ( Any, AsyncIterator, Callable, + Collection, Coroutine, Dict, List, @@ -814,7 +815,7 @@ class APIRouter(routing.Router): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -862,7 +863,7 @@ class APIRouter(routing.Router): def route( self, path: str, - methods: Optional[List[str]] = None, + methods: Optional[Collection[str]] = None, name: Optional[str] = None, include_in_schema: bool = True, ) -> Callable[[DecoratedCallable], DecoratedCallable]: @@ -1626,7 +1627,7 @@ class APIRouter(routing.Router): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -2003,7 +2004,7 @@ class APIRouter(routing.Router): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -2385,7 +2386,7 @@ class APIRouter(routing.Router): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -2767,7 +2768,7 @@ class APIRouter(routing.Router): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -3144,7 +3145,7 @@ class APIRouter(routing.Router): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -3521,7 +3522,7 @@ class APIRouter(routing.Router): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -3903,7 +3904,7 @@ class APIRouter(routing.Router): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, @@ -4285,7 +4286,7 @@ class APIRouter(routing.Router): This affects the generated OpenAPI (e.g. visible at `/docs`). Read more about it in the - [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-from-openapi). + [FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi). """ ), ] = True, diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py index 5ffad5986..88e394db1 100644 --- a/fastapi/security/oauth2.py +++ b/fastapi/security/oauth2.py @@ -85,7 +85,7 @@ class OAuth2PasswordRequestForm: ], password: Annotated[ str, - Form(), + Form(json_schema_extra={"format": "password"}), Doc( """ `password` string. The OAuth2 spec requires the exact field name @@ -130,7 +130,7 @@ class OAuth2PasswordRequestForm: ] = None, client_secret: Annotated[ Union[str, None], - Form(), + Form(json_schema_extra={"format": "password"}), Doc( """ If there's a `client_password` (and a `client_id`), they can be sent @@ -457,11 +457,26 @@ class OAuth2PasswordBearer(OAuth2): """ ), ] = True, + refreshUrl: Annotated[ + Optional[str], + Doc( + """ + The URL to refresh the token and obtain a new one. + """ + ), + ] = None, ): if not scopes: scopes = {} flows = OAuthFlowsModel( - password=cast(Any, {"tokenUrl": tokenUrl, "scopes": scopes}) + password=cast( + Any, + { + "tokenUrl": tokenUrl, + "refreshUrl": refreshUrl, + "scopes": scopes, + }, + ) ) super().__init__( flows=flows, diff --git a/pyproject.toml b/pyproject.toml index 1c540e2f6..7709451ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ classifiers = [ "Topic :: Internet :: WWW/HTTP", ] dependencies = [ - "starlette>=0.40.0,<0.47.0", + "starlette>=0.40.0,<0.48.0", "pydantic>=1.7.4,!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0", "typing-extensions>=4.8.0", ] @@ -58,7 +58,26 @@ Changelog = "https://fastapi.tiangolo.com/release-notes/" [project.optional-dependencies] standard = [ - "fastapi-cli[standard] >=0.0.5", + "fastapi-cli[standard] >=0.0.8", + # For the test client + "httpx >=0.23.0", + # For templates + "jinja2 >=3.1.5", + # For forms and file uploads + "python-multipart >=0.0.18", + # To validate email fields + "email-validator >=2.0.0", + # Uvicorn with uvloop + "uvicorn[standard] >=0.12.0", + # TODO: this should be part of some pydantic optional extra dependencies + # # Settings management + # "pydantic-settings >=2.0.0", + # # Extra Pydantic data types + # "pydantic-extra-types >=2.0.0", +] + +standard-no-fastapi-cloud-cli = [ + "fastapi-cli[standard-no-fastapi-cloud-cli] >=0.0.8", # For the test client "httpx >=0.23.0", # For templates @@ -77,7 +96,7 @@ standard = [ ] all = [ - "fastapi-cli[standard] >=0.0.5", + "fastapi-cli[standard] >=0.0.8", # # For the test client "httpx >=0.23.0", # For templates diff --git a/requirements-docs.txt b/requirements-docs.txt index 606314926..5c5701f73 100644 --- a/requirements-docs.txt +++ b/requirements-docs.txt @@ -1,6 +1,6 @@ -e . -r requirements-docs-tests.txt -mkdocs-material==9.6.1 +mkdocs-material==9.6.15 mdx-include >=1.4.1,<2.0.0 mkdocs-redirects>=1.2.1,<1.3.0 typer == 0.16.0 @@ -8,7 +8,7 @@ pyyaml >=5.3.1,<7.0.0 # For Material for MkDocs, Chinese search jieba==0.42.1 # For image processing by Material for MkDocs -pillow==11.1.0 +pillow==11.3.0 # For image processing by Material for MkDocs cairosvg==2.7.1 mkdocstrings[python]==0.26.1 diff --git a/scripts/label_approved.py b/scripts/label_approved.py index 271444504..81de92efb 100644 --- a/scripts/label_approved.py +++ b/scripts/label_approved.py @@ -27,7 +27,7 @@ if settings.debug: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.INFO) -logging.debug(f"Using config: {settings.json()}") +logging.debug(f"Using config: {settings.model_dump_json()}") g = Github(settings.token.get_secret_value()) repo = g.get_repo(settings.github_repository) for pr in repo.get_pulls(state="open"): @@ -48,7 +48,7 @@ for pr in repo.get_pulls(state="open"): ] config = settings.config or default_config for approved_label, conf in config.items(): - logging.debug(f"Processing config: {conf.json()}") + logging.debug(f"Processing config: {conf.model_dump_json()}") if conf.await_label is None or (conf.await_label in pr_label_by_name): logging.debug(f"Processable PR: {pr.number}") if len(approved_reviews) >= conf.number: diff --git a/scripts/people.py b/scripts/people.py index f61fd31c9..7418b4595 100644 --- a/scripts/people.py +++ b/scripts/people.py @@ -119,6 +119,7 @@ class Settings(BaseSettings): github_token: SecretStr github_repository: str httpx_timeout: int = 30 + sleep_interval: int = 5 def get_graphql_response( @@ -184,7 +185,7 @@ def get_discussion_nodes(settings: Settings) -> list[DiscussionsNode]: discussion_nodes.append(discussion_edge.node) last_edge = discussion_edges[-1] # Handle GitHub secondary rate limits, requests per minute - time.sleep(5) + time.sleep(settings.sleep_interval) discussion_edges = get_graphql_question_discussion_edges( settings=settings, after=last_edge.cursor ) diff --git a/tests/test_openapi_model_description_trim_on_formfeed.py b/tests/test_openapi_model_description_trim_on_formfeed.py new file mode 100644 index 000000000..e18d4f6b2 --- /dev/null +++ b/tests/test_openapi_model_description_trim_on_formfeed.py @@ -0,0 +1,31 @@ +from fastapi import FastAPI +from fastapi.testclient import TestClient +from pydantic import BaseModel + +app = FastAPI() + + +class MyModel(BaseModel): + """ + A model with a form feed character in the title. + \f + Text after form feed character. + """ + + +@app.get("/foo") +def foo(v: MyModel): # pragma: no cover + pass + + +client = TestClient(app) + + +def test_openapi(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + openapi_schema = response.json() + + assert openapi_schema["components"]["schemas"]["MyModel"]["description"] == ( + "A model with a form feed character in the title.\n" + ) diff --git a/tests/test_tutorial/test_security/test_tutorial003.py b/tests/test_tutorial/test_security/test_tutorial003.py index 37fc2618f..2bbb2e851 100644 --- a/tests/test_tutorial/test_security/test_tutorial003.py +++ b/tests/test_tutorial/test_security/test_tutorial003.py @@ -163,7 +163,11 @@ def test_openapi_schema(client: TestClient): } ), "username": {"title": "Username", "type": "string"}, - "password": {"title": "Password", "type": "string"}, + "password": { + "title": "Password", + "type": "string", + "format": "password", + }, "scope": {"title": "Scope", "type": "string", "default": ""}, "client_id": IsDict( { @@ -179,11 +183,16 @@ def test_openapi_schema(client: TestClient): { "title": "Client Secret", "anyOf": [{"type": "string"}, {"type": "null"}], + "format": "password", } ) | IsDict( # TODO: remove when deprecating Pydantic v1 - {"title": "Client Secret", "type": "string"} + { + "title": "Client Secret", + "type": "string", + "format": "password", + } ), }, }, diff --git a/tests/test_tutorial/test_security/test_tutorial005.py b/tests/test_tutorial/test_security/test_tutorial005.py index 88c3d7815..ad644d61b 100644 --- a/tests/test_tutorial/test_security/test_tutorial005.py +++ b/tests/test_tutorial/test_security/test_tutorial005.py @@ -377,7 +377,11 @@ def test_openapi_schema(mod: ModuleType): } ), "username": {"title": "Username", "type": "string"}, - "password": {"title": "Password", "type": "string"}, + "password": { + "title": "Password", + "type": "string", + "format": "password", + }, "scope": {"title": "Scope", "type": "string", "default": ""}, "client_id": IsDict( { @@ -393,11 +397,16 @@ def test_openapi_schema(mod: ModuleType): { "title": "Client Secret", "anyOf": [{"type": "string"}, {"type": "null"}], + "format": "password", } ) | IsDict( # TODO: remove when deprecating Pydantic v1 - {"title": "Client Secret", "type": "string"} + { + "title": "Client Secret", + "type": "string", + "format": "password", + } ), }, }, diff --git a/tests/test_tutorial/test_settings/test_tutorial001.py b/tests/test_tutorial/test_settings/test_tutorial001.py index eb30dbcee..92a5782d4 100644 --- a/tests/test_tutorial/test_settings/test_tutorial001.py +++ b/tests/test_tutorial/test_settings/test_tutorial001.py @@ -1,14 +1,26 @@ +import importlib + +import pytest from fastapi.testclient import TestClient from pytest import MonkeyPatch -from ...utils import needs_pydanticv2 +from ...utils import needs_pydanticv1, needs_pydanticv2 -@needs_pydanticv2 -def test_settings(monkeypatch: MonkeyPatch): +@pytest.fixture( + name="app", + params=[ + pytest.param("tutorial001", marks=needs_pydanticv2), + pytest.param("tutorial001_pv1", marks=needs_pydanticv1), + ], +) +def get_app(request: pytest.FixtureRequest, monkeypatch: MonkeyPatch): monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com") - from docs_src.settings.tutorial001 import app + mod = importlib.import_module(f"docs_src.settings.{request.param}") + return mod.app + +def test_settings(app): client = TestClient(app) response = client.get("/info") assert response.status_code == 200, response.text diff --git a/tests/test_tutorial/test_settings/test_tutorial001_pv1.py b/tests/test_tutorial/test_settings/test_tutorial001_pv1.py deleted file mode 100644 index e4659de66..000000000 --- a/tests/test_tutorial/test_settings/test_tutorial001_pv1.py +++ /dev/null @@ -1,19 +0,0 @@ -from fastapi.testclient import TestClient -from pytest import MonkeyPatch - -from ...utils import needs_pydanticv1 - - -@needs_pydanticv1 -def test_settings(monkeypatch: MonkeyPatch): - monkeypatch.setenv("ADMIN_EMAIL", "admin@example.com") - from docs_src.settings.tutorial001_pv1 import app - - client = TestClient(app) - response = client.get("/info") - assert response.status_code == 200, response.text - assert response.json() == { - "app_name": "Awesome API", - "admin_email": "admin@example.com", - "items_per_user": 50, - } diff --git a/tests/test_union_forms.py b/tests/test_union_forms.py new file mode 100644 index 000000000..cbe98ea82 --- /dev/null +++ b/tests/test_union_forms.py @@ -0,0 +1,156 @@ +from typing import Union + +from fastapi import FastAPI, Form +from fastapi.testclient import TestClient +from pydantic import BaseModel +from typing_extensions import Annotated + +app = FastAPI() + + +class UserForm(BaseModel): + name: str + email: str + + +class CompanyForm(BaseModel): + company_name: str + industry: str + + +@app.post("/form-union/") +def post_union_form(data: Annotated[Union[UserForm, CompanyForm], Form()]): + return {"received": data} + + +client = TestClient(app) + + +def test_post_user_form(): + response = client.post( + "/form-union/", data={"name": "John Doe", "email": "john@example.com"} + ) + assert response.status_code == 200, response.text + assert response.json() == { + "received": {"name": "John Doe", "email": "john@example.com"} + } + + +def test_post_company_form(): + response = client.post( + "/form-union/", data={"company_name": "Tech Corp", "industry": "Technology"} + ) + assert response.status_code == 200, response.text + assert response.json() == { + "received": {"company_name": "Tech Corp", "industry": "Technology"} + } + + +def test_invalid_form_data(): + response = client.post( + "/form-union/", + data={"name": "John", "company_name": "Tech Corp"}, + ) + assert response.status_code == 422, response.text + + +def test_empty_form(): + response = client.post("/form-union/") + assert response.status_code == 422, response.text + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/form-union/": { + "post": { + "summary": "Post Union Form", + "operationId": "post_union_form_form_union__post", + "requestBody": { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "anyOf": [ + {"$ref": "#/components/schemas/UserForm"}, + {"$ref": "#/components/schemas/CompanyForm"}, + ], + "title": "Data", + } + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "CompanyForm": { + "properties": { + "company_name": {"type": "string", "title": "Company Name"}, + "industry": {"type": "string", "title": "Industry"}, + }, + "type": "object", + "required": ["company_name", "industry"], + "title": "CompanyForm", + }, + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "UserForm": { + "properties": { + "name": {"type": "string", "title": "Name"}, + "email": {"type": "string", "title": "Email"}, + }, + "type": "object", + "required": ["name", "email"], + "title": "UserForm", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_validate_response_recursive/app_pv1.py b/tests/test_validate_response_recursive/app.py similarity index 79% rename from tests/test_validate_response_recursive/app_pv1.py rename to tests/test_validate_response_recursive/app.py index 4cfc4b3ee..d23d27980 100644 --- a/tests/test_validate_response_recursive/app_pv1.py +++ b/tests/test_validate_response_recursive/app.py @@ -1,6 +1,7 @@ from typing import List from fastapi import FastAPI +from fastapi._compat import PYDANTIC_V2 from pydantic import BaseModel app = FastAPI() @@ -11,9 +12,6 @@ class RecursiveItem(BaseModel): name: str -RecursiveItem.update_forward_refs() - - class RecursiveSubitemInSubmodel(BaseModel): sub_items2: List["RecursiveItemViaSubmodel"] = [] name: str @@ -24,7 +22,13 @@ class RecursiveItemViaSubmodel(BaseModel): name: str -RecursiveSubitemInSubmodel.update_forward_refs() +if PYDANTIC_V2: + RecursiveItem.model_rebuild() + RecursiveSubitemInSubmodel.model_rebuild() + RecursiveItemViaSubmodel.model_rebuild() +else: + RecursiveItem.update_forward_refs() + RecursiveSubitemInSubmodel.update_forward_refs() @app.get("/items/recursive", response_model=RecursiveItem) diff --git a/tests/test_validate_response_recursive/app_pv2.py b/tests/test_validate_response_recursive/app_pv2.py deleted file mode 100644 index 8c93a8349..000000000 --- a/tests/test_validate_response_recursive/app_pv2.py +++ /dev/null @@ -1,51 +0,0 @@ -from typing import List - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class RecursiveItem(BaseModel): - sub_items: List["RecursiveItem"] = [] - name: str - - -RecursiveItem.model_rebuild() - - -class RecursiveSubitemInSubmodel(BaseModel): - sub_items2: List["RecursiveItemViaSubmodel"] = [] - name: str - - -class RecursiveItemViaSubmodel(BaseModel): - sub_items1: List[RecursiveSubitemInSubmodel] = [] - name: str - - -RecursiveSubitemInSubmodel.model_rebuild() -RecursiveItemViaSubmodel.model_rebuild() - - -@app.get("/items/recursive", response_model=RecursiveItem) -def get_recursive(): - return {"name": "item", "sub_items": [{"name": "subitem", "sub_items": []}]} - - -@app.get("/items/recursive-submodel", response_model=RecursiveItemViaSubmodel) -def get_recursive_submodel(): - return { - "name": "item", - "sub_items1": [ - { - "name": "subitem", - "sub_items2": [ - { - "name": "subsubitem", - "sub_items1": [{"name": "subsubsubitem", "sub_items2": []}], - } - ], - } - ], - } diff --git a/tests/test_validate_response_recursive/test_validate_response_recursive_pv2.py b/tests/test_validate_response_recursive/test_validate_response_recursive.py similarity index 90% rename from tests/test_validate_response_recursive/test_validate_response_recursive_pv2.py rename to tests/test_validate_response_recursive/test_validate_response_recursive.py index 7d45e7fe4..21a299ab8 100644 --- a/tests/test_validate_response_recursive/test_validate_response_recursive_pv2.py +++ b/tests/test_validate_response_recursive/test_validate_response_recursive.py @@ -1,12 +1,9 @@ from fastapi.testclient import TestClient -from ..utils import needs_pydanticv2 +from .app import app -@needs_pydanticv2 def test_recursive(): - from .app_pv2 import app - client = TestClient(app) response = client.get("/items/recursive") assert response.status_code == 200, response.text diff --git a/tests/test_validate_response_recursive/test_validate_response_recursive_pv1.py b/tests/test_validate_response_recursive/test_validate_response_recursive_pv1.py deleted file mode 100644 index de578ae03..000000000 --- a/tests/test_validate_response_recursive/test_validate_response_recursive_pv1.py +++ /dev/null @@ -1,33 +0,0 @@ -from fastapi.testclient import TestClient - -from ..utils import needs_pydanticv1 - - -@needs_pydanticv1 -def test_recursive(): - from .app_pv1 import app - - client = TestClient(app) - response = client.get("/items/recursive") - assert response.status_code == 200, response.text - assert response.json() == { - "sub_items": [{"name": "subitem", "sub_items": []}], - "name": "item", - } - - response = client.get("/items/recursive-submodel") - assert response.status_code == 200, response.text - assert response.json() == { - "name": "item", - "sub_items1": [ - { - "name": "subitem", - "sub_items2": [ - { - "name": "subsubitem", - "sub_items1": [{"name": "subsubsubitem", "sub_items2": []}], - } - ], - } - ], - }