mirror of
https://github.com/fastapi/fastapi.git
synced 2025-12-27 00:01:03 -05:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4efae81a76 | ||
|
|
3690140555 | ||
|
|
ad4d8f24ca | ||
|
|
ac438b9934 | ||
|
|
425a4c5bb1 | ||
|
|
3a223b9073 | ||
|
|
566e0d60b2 | ||
|
|
940ee0c9c3 | ||
|
|
f8df43d734 | ||
|
|
dbb7020a4d | ||
|
|
32da8ca78b | ||
|
|
8c42d0ce16 | ||
|
|
2a25f6d3a3 | ||
|
|
8be5867de7 | ||
|
|
fad35ef43f | ||
|
|
4d57c13055 | ||
|
|
496de1816a | ||
|
|
2cf04ee30d | ||
|
|
ec00f5a90f | ||
|
|
8b46d8821b | ||
|
|
17fcbbe910 | ||
|
|
dcfb8b9dda | ||
|
|
1fc586c3a5 | ||
|
|
bb88a0f94a | ||
|
|
9d1a384f4f | ||
|
|
c144f9fbd3 |
@@ -1,11 +1,11 @@
|
||||
tiangolo:
|
||||
login: tiangolo
|
||||
count: 782
|
||||
count: 794
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
|
||||
url: https://github.com/tiangolo
|
||||
dependabot:
|
||||
login: dependabot
|
||||
count: 117
|
||||
count: 126
|
||||
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: 45
|
||||
count: 49
|
||||
avatarUrl: https://avatars.githubusercontent.com/in/68672?v=4
|
||||
url: https://github.com/apps/pre-commit-ci
|
||||
github-actions:
|
||||
@@ -25,7 +25,7 @@ github-actions:
|
||||
url: https://github.com/apps/github-actions
|
||||
Kludex:
|
||||
login: Kludex
|
||||
count: 24
|
||||
count: 25
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7353520?u=df8a3f06ba8f55ae1967a3e2d5ed882903a4e330&v=4
|
||||
url: https://github.com/Kludex
|
||||
dmontagu:
|
||||
@@ -33,36 +33,36 @@ dmontagu:
|
||||
count: 17
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/35119617?u=540f30c937a6450812628b9592a1dfe91bbe148e&v=4
|
||||
url: https://github.com/dmontagu
|
||||
YuriiMotov:
|
||||
login: YuriiMotov
|
||||
count: 15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=b9b13d598dddfab529a52d264df80a900bfe7060&v=4
|
||||
url: https://github.com/YuriiMotov
|
||||
nilslindemann:
|
||||
login: nilslindemann
|
||||
count: 14
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
|
||||
url: https://github.com/nilslindemann
|
||||
euri10:
|
||||
login: euri10
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1104190?u=321a2e953e6645a7d09b732786c7a8061e0f8a8b&v=4
|
||||
url: https://github.com/euri10
|
||||
nilslindemann:
|
||||
login: nilslindemann
|
||||
svlandeg:
|
||||
login: svlandeg
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
|
||||
url: https://github.com/nilslindemann
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4
|
||||
url: https://github.com/svlandeg
|
||||
kantandane:
|
||||
login: kantandane
|
||||
count: 13
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3978368?u=cccc199291f991a73b1ebba5abc735a948e0bd16&v=4
|
||||
url: https://github.com/kantandane
|
||||
svlandeg:
|
||||
login: svlandeg
|
||||
count: 11
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8796347?u=556c97650c27021911b0b9447ec55e75987b0e8a&v=4
|
||||
url: https://github.com/svlandeg
|
||||
zhaohan-dong:
|
||||
login: zhaohan-dong
|
||||
count: 11
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/65422392?u=8260f8781f50248410ebfa4c9bf70e143fe5c9f2&v=4
|
||||
url: https://github.com/zhaohan-dong
|
||||
YuriiMotov:
|
||||
login: YuriiMotov
|
||||
count: 10
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/109919500?u=b9b13d598dddfab529a52d264df80a900bfe7060&v=4
|
||||
url: https://github.com/YuriiMotov
|
||||
mariacamilagl:
|
||||
login: mariacamilagl
|
||||
count: 9
|
||||
@@ -158,6 +158,11 @@ prostomarkeloff:
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/28061158?u=6918e39a1224194ba636e897461a02a20126d7ad&v=4
|
||||
url: https://github.com/prostomarkeloff
|
||||
frankie567:
|
||||
login: frankie567
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=f3e79acfe4ed207e15c2145161a8a9759925fcd2&v=4
|
||||
url: https://github.com/frankie567
|
||||
nsidnev:
|
||||
login: nsidnev
|
||||
count: 3
|
||||
@@ -191,7 +196,7 @@ Serrones:
|
||||
uriyyo:
|
||||
login: uriyyo
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/32038156?u=0c68019beb28381ce5205a838937c61e0fe3fee2&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/32038156?u=c26ca9b821fcf6499b84db75f553d4980bf8d023&v=4
|
||||
url: https://github.com/uriyyo
|
||||
andrew222651:
|
||||
login: andrew222651
|
||||
@@ -261,7 +266,7 @@ Nimitha-jagadeesha:
|
||||
lucaromagnoli:
|
||||
login: lucaromagnoli
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/38782977?u=e66396859f493b4ddcb3a837a1b2b2039c805417&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/38782977?u=15df02e806a2293af40ac619fba11dbe3c0c4fd4&v=4
|
||||
url: https://github.com/lucaromagnoli
|
||||
salmantec:
|
||||
login: salmantec
|
||||
@@ -328,11 +333,6 @@ svalouch:
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/54674660?v=4
|
||||
url: https://github.com/svalouch
|
||||
frankie567:
|
||||
login: frankie567
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1144727?u=f3e79acfe4ed207e15c2145161a8a9759925fcd2&v=4
|
||||
url: https://github.com/frankie567
|
||||
marier-nico:
|
||||
login: marier-nico
|
||||
count: 2
|
||||
@@ -346,7 +346,7 @@ Dustyposa:
|
||||
aviramha:
|
||||
login: aviramha
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/41201924?u=6883cc4fc13a7b2e60d4deddd4be06f9c5287880&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/41201924?u=ce5d3ea7037c2e6b3f82eff87e2217d4fb63214b&v=4
|
||||
url: https://github.com/aviramha
|
||||
iwpnd:
|
||||
login: iwpnd
|
||||
|
||||
@@ -14,6 +14,9 @@ sponsors:
|
||||
- login: coderabbitai
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/132028505?v=4
|
||||
url: https://github.com/coderabbitai
|
||||
- login: greptileai
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/140149887?v=4
|
||||
url: https://github.com/greptileai
|
||||
- login: subtotal
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/176449348?v=4
|
||||
url: https://github.com/subtotal
|
||||
@@ -41,9 +44,9 @@ sponsors:
|
||||
- login: permitio
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/71775833?v=4
|
||||
url: https://github.com/permitio
|
||||
- - login: marvin-robot
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/41086007?u=b9fcab402d0cd0aec738b6574fe60855cb0cd36d&v=4
|
||||
url: https://github.com/marvin-robot
|
||||
- - login: BoostryJP
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4
|
||||
url: https://github.com/BoostryJP
|
||||
- login: mercedes-benz
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/34240465?v=4
|
||||
url: https://github.com/mercedes-benz
|
||||
@@ -53,9 +56,9 @@ sponsors:
|
||||
- login: LambdaTest-Inc
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/171592363?u=96606606a45fa170427206199014f2a5a2a4920b&v=4
|
||||
url: https://github.com/LambdaTest-Inc
|
||||
- login: BoostryJP
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/57932412?v=4
|
||||
url: https://github.com/BoostryJP
|
||||
- login: requestly
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/12287519?v=4
|
||||
url: https://github.com/requestly
|
||||
- login: acsone
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7601056?v=4
|
||||
url: https://github.com/acsone
|
||||
@@ -71,27 +74,39 @@ sponsors:
|
||||
- - login: mainframeindustries
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/55092103?v=4
|
||||
url: https://github.com/mainframeindustries
|
||||
- login: yasyf
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/709645?u=f36736b3c6a85f578886ecc42a740e7b436e7a01&v=4
|
||||
url: https://github.com/yasyf
|
||||
- - login: alixlahuec
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/29543316?u=44357eb2a93bccf30fb9d389b8befe94a3d00985&v=4
|
||||
url: https://github.com/alixlahuec
|
||||
- login: Partho
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2034301?u=ce195ac36835cca0cdfe6dd6e897bd38873a1524&v=4
|
||||
url: https://github.com/Partho
|
||||
- - login: primer-io
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62146168?v=4
|
||||
url: https://github.com/primer-io
|
||||
- - login: nilslindemann
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
|
||||
url: https://github.com/nilslindemann
|
||||
- login: upciti
|
||||
- login: xsalagarcia
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/66035908?v=4
|
||||
url: https://github.com/xsalagarcia
|
||||
- - login: upciti
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43346262?v=4
|
||||
url: https://github.com/upciti
|
||||
- login: thisisfixer
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/14433035?u=076d52a5b7891c764904af9f462bfb45428e25df&v=4
|
||||
url: https://github.com/thisisfixer
|
||||
- login: GonnaFlyMethod
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/60840539?u=edf70b373fd4f1a83d3eb7c6802f4b6addb572cf&v=4
|
||||
url: https://github.com/GonnaFlyMethod
|
||||
- login: ChargeStorm
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/26000165?v=4
|
||||
url: https://github.com/ChargeStorm
|
||||
- login: DanielYang59
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/80093591?u=63873f701c7c74aac83c906800a1dddc0bc8c92f&v=4
|
||||
url: https://github.com/DanielYang59
|
||||
- login: nilslindemann
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
|
||||
url: https://github.com/nilslindemann
|
||||
- - login: samuelcolvin
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4039449?u=42eb3b833047c8c4b4f647a031eaef148c16d93f&v=4
|
||||
url: https://github.com/samuelcolvin
|
||||
- login: vincentkoc
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/25068?u=fbd5b2d51142daa4bdbc21e21953a3b8b8188a4a&v=4
|
||||
url: https://github.com/vincentkoc
|
||||
- login: otosky
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/42260747?u=69d089387c743d89427aa4ad8740cfb34045a9e0&v=4
|
||||
url: https://github.com/otosky
|
||||
@@ -101,6 +116,9 @@ sponsors:
|
||||
- login: roboflow
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/53104118?v=4
|
||||
url: https://github.com/roboflow
|
||||
- login: dudikbender
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=3a57542938ebfd57579a0111db2b297e606d9681&v=4
|
||||
url: https://github.com/dudikbender
|
||||
- login: ehaca
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/25950317?u=cec1a3e0643b785288ae8260cc295a85ab344995&v=4
|
||||
url: https://github.com/ehaca
|
||||
@@ -113,21 +131,15 @@ sponsors:
|
||||
- login: Leay15
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/32212558?u=c4aa9c1737e515959382a5515381757b1fd86c53&v=4
|
||||
url: https://github.com/Leay15
|
||||
- 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
|
||||
- login: Karine-Bauch
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/90465103?u=7feb1018abb1a5631cfd9a91fea723d1ceb5f49b&v=4
|
||||
url: https://github.com/Karine-Bauch
|
||||
- login: jugeeem
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/116043716?u=ae590d79c38ac79c91b9c5caa6887d061e865a3d&v=4
|
||||
url: https://github.com/jugeeem
|
||||
- login: dudikbender
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/53487583?u=3a57542938ebfd57579a0111db2b297e606d9681&v=4
|
||||
url: https://github.com/dudikbender
|
||||
- login: connorpark24
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/142128990?u=09b84a4beb1f629b77287a837bcf3729785cdd89&v=4
|
||||
url: https://github.com/connorpark24
|
||||
- login: patsatsia
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/61111267?u=3271b85f7a37b479c8d0ae0a235182e83c166edf&v=4
|
||||
url: https://github.com/patsatsia
|
||||
@@ -140,9 +152,12 @@ sponsors:
|
||||
- login: chickenandstats
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/79477966?u=ae2b894aa954070db1d7830dab99b49eba4e4567&v=4
|
||||
url: https://github.com/chickenandstats
|
||||
- login: dodo5522
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1362607?u=9bf1e0e520cccc547c046610c468ce6115bbcf9f&v=4
|
||||
url: https://github.com/dodo5522
|
||||
- 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
|
||||
- login: knallgelb
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/2358812?u=c48cb6362b309d74cbf144bd6ad3aed3eb443e82&v=4
|
||||
url: https://github.com/knallgelb
|
||||
@@ -170,9 +185,12 @@ sponsors:
|
||||
- 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
|
||||
- login: jaredtrog
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4381365?v=4
|
||||
url: https://github.com/jaredtrog
|
||||
- login: oliverxchen
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4471774?u=534191f25e32eeaadda22dfab4b0a428733d5489&v=4
|
||||
url: https://github.com/oliverxchen
|
||||
- login: jstanden
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/63288?u=c3658d57d2862c607a0e19c2101c3c51876e36ad&v=4
|
||||
url: https://github.com/jstanden
|
||||
@@ -197,6 +215,9 @@ sponsors:
|
||||
- login: mintuhouse
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/769950?u=ecfbd79a97d33177e0d093ddb088283cf7fe8444&v=4
|
||||
url: https://github.com/mintuhouse
|
||||
- login: dodo5522
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1362607?u=9bf1e0e520cccc547c046610c468ce6115bbcf9f&v=4
|
||||
url: https://github.com/dodo5522
|
||||
- login: wdwinslow
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/11562137?u=371272f2c69e680e0559a7b0a57385e83a5dc728&v=4
|
||||
url: https://github.com/wdwinslow
|
||||
@@ -212,18 +233,15 @@ sponsors:
|
||||
- login: mjohnsey
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16784016?u=38fad2e6b411244560b3af99c5f5a4751bc81865&v=4
|
||||
url: https://github.com/mjohnsey
|
||||
- login: enguy-hub
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/16822912?u=2c45f9e7f427b2f2f3b023d7fdb0d44764c92ae8&v=4
|
||||
url: https://github.com/enguy-hub
|
||||
- login: ashi-agrawal
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/17105294?u=99c7a854035e5398d8e7b674f2d42baae6c957f8&v=4
|
||||
url: https://github.com/ashi-agrawal
|
||||
- login: RaamEEIL
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/20320552?v=4
|
||||
url: https://github.com/RaamEEIL
|
||||
- login: jaredtrog
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4381365?v=4
|
||||
url: https://github.com/jaredtrog
|
||||
- login: oliverxchen
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4471774?u=534191f25e32eeaadda22dfab4b0a428733d5489&v=4
|
||||
url: https://github.com/oliverxchen
|
||||
- login: ternaus
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5481618?u=513a26b02a39e7a28d587cd37c6cc877ea368e6e&v=4
|
||||
url: https://github.com/ternaus
|
||||
@@ -242,7 +260,10 @@ sponsors:
|
||||
- - login: manoelpqueiroz
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/23669137?u=b12e84b28a84369ab5b30bd5a79e5788df5a0756&v=4
|
||||
url: https://github.com/manoelpqueiroz
|
||||
- - login: pawamoy
|
||||
- - login: ceb10n
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4
|
||||
url: https://github.com/ceb10n
|
||||
- login: pawamoy
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/3999221?u=b030e4c89df2f3a36bc4710b925bdeb6745c9856&v=4
|
||||
url: https://github.com/pawamoy
|
||||
- login: siavashyj
|
||||
@@ -260,9 +281,9 @@ sponsors:
|
||||
- login: hgalytoby
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/50397689?u=6cc9028f3db63f8f60ad21c17b1ce4b88c4e2e60&v=4
|
||||
url: https://github.com/hgalytoby
|
||||
- login: nisutec
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/25281462?u=e562484c451fdfc59053163f64405f8eb262b8b0&v=4
|
||||
url: https://github.com/nisutec
|
||||
- login: johnl28
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/54412955?u=47dd06082d1c39caa90c752eb55566e4f3813957&v=4
|
||||
url: https://github.com/johnl28
|
||||
- login: hoenie-ams
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/25708487?u=cda07434f0509ac728d9edf5e681117c0f6b818b&v=4
|
||||
url: https://github.com/hoenie-ams
|
||||
@@ -278,33 +299,21 @@ sponsors:
|
||||
- login: petercool
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/37613029?u=75aa8c6729e6e8f85a300561c4dbeef9d65c8797&v=4
|
||||
url: https://github.com/petercool
|
||||
- login: JulioPeixoto
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/96303574?u=27d4614350cae33653f1be35cb47c92a12627ac9&v=4
|
||||
url: https://github.com/JulioPeixoto
|
||||
- login: johnl28
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/54412955?u=47dd06082d1c39caa90c752eb55566e4f3813957&v=4
|
||||
url: https://github.com/johnl28
|
||||
- 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: miguelgr
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1484589?u=54556072b8136efa12ae3b6902032ea2a39ace4b&v=4
|
||||
url: https://github.com/miguelgr
|
||||
- login: WillHogan
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=8a80356e3e7d5a417157aba7ea565dabc8678327&v=4
|
||||
url: https://github.com/WillHogan
|
||||
- login: my3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1825270?v=4
|
||||
url: https://github.com/my3
|
||||
- login: Alisa-lisa
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4137964?u=e7e393504f554f4ff15863a1e01a5746863ef9ce&v=4
|
||||
url: https://github.com/Alisa-lisa
|
||||
- login: moonape1226
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8532038?u=d9f8b855a429fff9397c3833c2ff83849ebf989d&v=4
|
||||
url: https://github.com/moonape1226
|
||||
- login: danielunderwood
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4472301?v=4
|
||||
url: https://github.com/danielunderwood
|
||||
- login: rangulvers
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5235430?u=e254d4af4ace5a05fa58372ae677c7d26f0d5a53&v=4
|
||||
url: https://github.com/rangulvers
|
||||
- login: ddanier
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/113563?u=ed1dc79de72f93bd78581f88ebc6952b62f472da&v=4
|
||||
url: https://github.com/ddanier
|
||||
@@ -314,24 +323,18 @@ sponsors:
|
||||
- login: slafs
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/210173?v=4
|
||||
url: https://github.com/slafs
|
||||
- login: ceb10n
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/235213?u=edcce471814a1eba9f0cdaa4cd0de18921a940a6&v=4
|
||||
url: https://github.com/ceb10n
|
||||
- login: tochikuji
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/851759?v=4
|
||||
url: https://github.com/tochikuji
|
||||
- login: xncbf
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9462045?u=a80a7bb349555b277645632ed66639ff43400614&v=4
|
||||
url: https://github.com/xncbf
|
||||
- login: DMantis
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9536869?u=652dd0d49717803c0cbcbf44f7740e53cf2d4892&v=4
|
||||
url: https://github.com/DMantis
|
||||
- login: miguelgr
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1484589?u=54556072b8136efa12ae3b6902032ea2a39ace4b&v=4
|
||||
url: https://github.com/miguelgr
|
||||
- login: WillHogan
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1661551?u=8a80356e3e7d5a417157aba7ea565dabc8678327&v=4
|
||||
url: https://github.com/WillHogan
|
||||
- login: hard-coders
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9651103?u=95db33927bbff1ed1c07efddeb97ac2ff33068ed&v=4
|
||||
url: https://github.com/hard-coders
|
||||
- login: supdann
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9986994?u=9671810f4ae9504c063227fee34fd47567ff6954&v=4
|
||||
url: https://github.com/supdann
|
||||
- login: mntolia
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/10390224?v=4
|
||||
url: https://github.com/mntolia
|
||||
@@ -344,12 +347,9 @@ sponsors:
|
||||
- login: joshuatz
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/17817563?u=f1bf05b690d1fc164218f0b420cdd3acb7913e21&v=4
|
||||
url: https://github.com/joshuatz
|
||||
- login: danielunderwood
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/4472301?v=4
|
||||
url: https://github.com/danielunderwood
|
||||
- login: rangulvers
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5235430?u=e254d4af4ace5a05fa58372ae677c7d26f0d5a53&v=4
|
||||
url: https://github.com/rangulvers
|
||||
- login: nisutec
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/25281462?u=e562484c451fdfc59053163f64405f8eb262b8b0&v=4
|
||||
url: https://github.com/nisutec
|
||||
- login: sdevkota
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5250987?u=4ed9a120c89805a8aefda1cbdc0cf6512e64d1b4&v=4
|
||||
url: https://github.com/sdevkota
|
||||
@@ -365,39 +365,45 @@ sponsors:
|
||||
- login: harsh183
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/7780198?v=4
|
||||
url: https://github.com/harsh183
|
||||
- - login: KOZ39
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/38822500?u=9dfc0a697df1c9628f08e20dc3fb17b1afc4e5a7&v=4
|
||||
url: https://github.com/KOZ39
|
||||
- login: rwxd
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=cd04a39e3655923be4f25c2ba8a5a07b3da3230a&v=4
|
||||
url: https://github.com/rwxd
|
||||
- login: morzan1001
|
||||
- login: moonape1226
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/8532038?u=d9f8b855a429fff9397c3833c2ff83849ebf989d&v=4
|
||||
url: https://github.com/moonape1226
|
||||
- login: xncbf
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9462045?u=a80a7bb349555b277645632ed66639ff43400614&v=4
|
||||
url: https://github.com/xncbf
|
||||
- login: DMantis
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/9536869?u=652dd0d49717803c0cbcbf44f7740e53cf2d4892&v=4
|
||||
url: https://github.com/DMantis
|
||||
- - login: morzan1001
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/47593005?u=c30ab7230f82a12a9b938dcb54f84a996931409a&v=4
|
||||
url: https://github.com/morzan1001
|
||||
- login: azharthegeek
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/51288109?u=0987b2a9f39c21ccb071b6bdce0fc60d8492f8e8&v=4
|
||||
url: https://github.com/azharthegeek
|
||||
- login: Olegt0rr
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/25399456?u=3e87b5239a2f4600975ba13be73054f8567c6060&v=4
|
||||
url: https://github.com/Olegt0rr
|
||||
- login: larsyngvelundin
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/34173819?u=74958599695bf83ac9f1addd935a51548a10c6b0&v=4
|
||||
url: https://github.com/larsyngvelundin
|
||||
- login: andrecorumba
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/37807517?u=9b9be3b41da9bda60957da9ef37b50dbf65baa61&v=4
|
||||
url: https://github.com/andrecorumba
|
||||
- login: ChenPu2002
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/113831763?v=4
|
||||
url: https://github.com/ChenPu2002
|
||||
- login: KOZ39
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/38822500?u=9dfc0a697df1c9628f08e20dc3fb17b1afc4e5a7&v=4
|
||||
url: https://github.com/KOZ39
|
||||
- login: rwxd
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/40308458?u=cd04a39e3655923be4f25c2ba8a5a07b3da3230a&v=4
|
||||
url: https://github.com/rwxd
|
||||
- login: hippoley
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/135493401?u=1164ef48a645a7c12664fabc1638fbb7e1c459b0&v=4
|
||||
url: https://github.com/hippoley
|
||||
- login: CoderDeltaLAN
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/152043745?u=4ff541efffb7d134e60c5fcf2dd1e343f90bb782&v=4
|
||||
url: https://github.com/CoderDeltaLAN
|
||||
- login: aghents
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/60949885?u=d8616ddf22cf998a712cdceefd6a0256a178fe9d&v=4
|
||||
url: https://github.com/aghents
|
||||
- login: 0ne-stone
|
||||
- login: chris1ding1
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/194386334?u=5500604b50e35ed8a5aeb82ce34aa5d3ee3f88c7&v=4
|
||||
url: https://github.com/chris1ding1
|
||||
- login: onestn
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62360849?u=746dd21c34e7e06eefb11b03e8bb01aaae3c2a4f&v=4
|
||||
url: https://github.com/0ne-stone
|
||||
url: https://github.com/onestn
|
||||
- login: Rubinskiy
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/62457878?u=f2e35ed3d196a99cfadb5a29a91950342af07e34&v=4
|
||||
url: https://github.com/Rubinskiy
|
||||
- login: nayasinghania
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/74111380?u=752e99a5e139389fdc0a0677122adc08438eb076&v=4
|
||||
url: https://github.com/nayasinghania
|
||||
@@ -407,6 +413,9 @@ sponsors:
|
||||
- login: andreagrandi
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/636391?u=13d90cb8ec313593a5b71fbd4e33b78d6da736f5&v=4
|
||||
url: https://github.com/andreagrandi
|
||||
- login: Olegt0rr
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/25399456?u=3e87b5239a2f4600975ba13be73054f8567c6060&v=4
|
||||
url: https://github.com/Olegt0rr
|
||||
- login: msserpa
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6334934?u=82c4489eb1559d88d2990d60001901b14f722bbb&v=4
|
||||
url: https://github.com/msserpa
|
||||
|
||||
@@ -1,81 +1,86 @@
|
||||
- name: full-stack-fastapi-template
|
||||
html_url: https://github.com/fastapi/full-stack-fastapi-template
|
||||
stars: 38085
|
||||
stars: 38779
|
||||
owner_login: fastapi
|
||||
owner_html_url: https://github.com/fastapi
|
||||
- name: Hello-Python
|
||||
html_url: https://github.com/mouredev/Hello-Python
|
||||
stars: 32243
|
||||
stars: 32726
|
||||
owner_login: mouredev
|
||||
owner_html_url: https://github.com/mouredev
|
||||
- name: serve
|
||||
html_url: https://github.com/jina-ai/serve
|
||||
stars: 21754
|
||||
stars: 21779
|
||||
owner_login: jina-ai
|
||||
owner_html_url: https://github.com/jina-ai
|
||||
- name: HivisionIDPhotos
|
||||
html_url: https://github.com/Zeyi-Lin/HivisionIDPhotos
|
||||
stars: 19400
|
||||
stars: 20028
|
||||
owner_login: Zeyi-Lin
|
||||
owner_html_url: https://github.com/Zeyi-Lin
|
||||
- name: sqlmodel
|
||||
html_url: https://github.com/fastapi/sqlmodel
|
||||
stars: 16859
|
||||
stars: 17038
|
||||
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: 14452
|
||||
stars: 14786
|
||||
owner_login: Evil0ctal
|
||||
owner_html_url: https://github.com/Evil0ctal
|
||||
- name: fastapi-best-practices
|
||||
html_url: https://github.com/zhanymkanov/fastapi-best-practices
|
||||
stars: 13613
|
||||
stars: 13968
|
||||
owner_login: zhanymkanov
|
||||
owner_html_url: https://github.com/zhanymkanov
|
||||
- name: machine-learning-zoomcamp
|
||||
html_url: https://github.com/DataTalksClub/machine-learning-zoomcamp
|
||||
stars: 12171
|
||||
owner_login: DataTalksClub
|
||||
owner_html_url: https://github.com/DataTalksClub
|
||||
- name: fastapi_mcp
|
||||
html_url: https://github.com/tadata-org/fastapi_mcp
|
||||
stars: 10624
|
||||
stars: 10976
|
||||
owner_login: tadata-org
|
||||
owner_html_url: https://github.com/tadata-org
|
||||
- name: awesome-fastapi
|
||||
html_url: https://github.com/mjhea0/awesome-fastapi
|
||||
stars: 10415
|
||||
stars: 10618
|
||||
owner_login: mjhea0
|
||||
owner_html_url: https://github.com/mjhea0
|
||||
- name: FastUI
|
||||
html_url: https://github.com/pydantic/FastUI
|
||||
stars: 8879
|
||||
owner_login: pydantic
|
||||
owner_html_url: https://github.com/pydantic
|
||||
- name: XHS-Downloader
|
||||
html_url: https://github.com/JoeanAmier/XHS-Downloader
|
||||
stars: 8824
|
||||
owner_login: JoeanAmier
|
||||
owner_html_url: https://github.com/JoeanAmier
|
||||
- name: SurfSense
|
||||
html_url: https://github.com/MODSetter/SurfSense
|
||||
stars: 8257
|
||||
stars: 10243
|
||||
owner_login: MODSetter
|
||||
owner_html_url: https://github.com/MODSetter
|
||||
- name: FileCodeBox
|
||||
html_url: https://github.com/vastsa/FileCodeBox
|
||||
stars: 7367
|
||||
owner_login: vastsa
|
||||
owner_html_url: https://github.com/vastsa
|
||||
- name: XHS-Downloader
|
||||
html_url: https://github.com/JoeanAmier/XHS-Downloader
|
||||
stars: 9062
|
||||
owner_login: JoeanAmier
|
||||
owner_html_url: https://github.com/JoeanAmier
|
||||
- name: FastUI
|
||||
html_url: https://github.com/pydantic/FastUI
|
||||
stars: 8892
|
||||
owner_login: pydantic
|
||||
owner_html_url: https://github.com/pydantic
|
||||
- name: polar
|
||||
html_url: https://github.com/polarsource/polar
|
||||
stars: 7291
|
||||
stars: 8084
|
||||
owner_login: polarsource
|
||||
owner_html_url: https://github.com/polarsource
|
||||
- name: FileCodeBox
|
||||
html_url: https://github.com/vastsa/FileCodeBox
|
||||
stars: 7494
|
||||
owner_login: vastsa
|
||||
owner_html_url: https://github.com/vastsa
|
||||
- name: nonebot2
|
||||
html_url: https://github.com/nonebot/nonebot2
|
||||
stars: 7065
|
||||
stars: 7128
|
||||
owner_login: nonebot
|
||||
owner_html_url: https://github.com/nonebot
|
||||
- name: hatchet
|
||||
html_url: https://github.com/hatchet-dev/hatchet
|
||||
stars: 6070
|
||||
stars: 6155
|
||||
owner_login: hatchet-dev
|
||||
owner_html_url: https://github.com/hatchet-dev
|
||||
- name: serge
|
||||
@@ -85,27 +90,27 @@
|
||||
owner_html_url: https://github.com/serge-chat
|
||||
- name: fastapi-users
|
||||
html_url: https://github.com/fastapi-users/fastapi-users
|
||||
stars: 5599
|
||||
stars: 5683
|
||||
owner_login: fastapi-users
|
||||
owner_html_url: https://github.com/fastapi-users
|
||||
- name: strawberry
|
||||
html_url: https://github.com/strawberry-graphql/strawberry
|
||||
stars: 4422
|
||||
stars: 4452
|
||||
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
|
||||
stars: 4296
|
||||
owner_login: chatpire
|
||||
owner_html_url: https://github.com/chatpire
|
||||
- name: poem
|
||||
html_url: https://github.com/poem-web/poem
|
||||
stars: 4197
|
||||
stars: 4235
|
||||
owner_login: poem-web
|
||||
owner_html_url: https://github.com/poem-web
|
||||
- name: dynaconf
|
||||
html_url: https://github.com/dynaconf/dynaconf
|
||||
stars: 4144
|
||||
stars: 4174
|
||||
owner_login: dynaconf
|
||||
owner_html_url: https://github.com/dynaconf
|
||||
- name: atrilabs-engine
|
||||
@@ -115,42 +120,42 @@
|
||||
owner_html_url: https://github.com/Atri-Labs
|
||||
- name: Kokoro-FastAPI
|
||||
html_url: https://github.com/remsky/Kokoro-FastAPI
|
||||
stars: 3739
|
||||
stars: 3875
|
||||
owner_login: remsky
|
||||
owner_html_url: https://github.com/remsky
|
||||
- name: logfire
|
||||
html_url: https://github.com/pydantic/logfire
|
||||
stars: 3614
|
||||
stars: 3717
|
||||
owner_login: pydantic
|
||||
owner_html_url: https://github.com/pydantic
|
||||
- name: LitServe
|
||||
html_url: https://github.com/Lightning-AI/LitServe
|
||||
stars: 3578
|
||||
stars: 3615
|
||||
owner_login: Lightning-AI
|
||||
owner_html_url: https://github.com/Lightning-AI
|
||||
- name: datamodel-code-generator
|
||||
html_url: https://github.com/koxudaxi/datamodel-code-generator
|
||||
stars: 3496
|
||||
stars: 3554
|
||||
owner_login: koxudaxi
|
||||
owner_html_url: https://github.com/koxudaxi
|
||||
- name: farfalle
|
||||
html_url: https://github.com/rashadphz/farfalle
|
||||
stars: 3459
|
||||
owner_login: rashadphz
|
||||
owner_html_url: https://github.com/rashadphz
|
||||
- name: fastapi-admin
|
||||
html_url: https://github.com/fastapi-admin/fastapi-admin
|
||||
stars: 3456
|
||||
owner_login: fastapi-admin
|
||||
owner_html_url: https://github.com/fastapi-admin
|
||||
- name: huma
|
||||
html_url: https://github.com/danielgtaylor/huma
|
||||
stars: 3447
|
||||
stars: 3521
|
||||
owner_login: danielgtaylor
|
||||
owner_html_url: https://github.com/danielgtaylor
|
||||
- name: fastapi-admin
|
||||
html_url: https://github.com/fastapi-admin/fastapi-admin
|
||||
stars: 3497
|
||||
owner_login: fastapi-admin
|
||||
owner_html_url: https://github.com/fastapi-admin
|
||||
- name: farfalle
|
||||
html_url: https://github.com/rashadphz/farfalle
|
||||
stars: 3476
|
||||
owner_login: rashadphz
|
||||
owner_html_url: https://github.com/rashadphz
|
||||
- name: tracecat
|
||||
html_url: https://github.com/TracecatHQ/tracecat
|
||||
stars: 3254
|
||||
stars: 3310
|
||||
owner_login: TracecatHQ
|
||||
owner_html_url: https://github.com/TracecatHQ
|
||||
- name: opyrator
|
||||
@@ -160,336 +165,331 @@
|
||||
owner_html_url: https://github.com/ml-tooling
|
||||
- name: docarray
|
||||
html_url: https://github.com/docarray/docarray
|
||||
stars: 3107
|
||||
stars: 3108
|
||||
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: 2936
|
||||
stars: 2945
|
||||
owner_login: nsidnev
|
||||
owner_html_url: https://github.com/nsidnev
|
||||
- name: uvicorn-gunicorn-fastapi-docker
|
||||
html_url: https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker
|
||||
stars: 2804
|
||||
stars: 2809
|
||||
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: 2610
|
||||
owner_login: ml-tooling
|
||||
owner_html_url: https://github.com/ml-tooling
|
||||
- name: devpush
|
||||
html_url: https://github.com/hunvreus/devpush
|
||||
stars: 2784
|
||||
owner_login: hunvreus
|
||||
owner_html_url: https://github.com/hunvreus
|
||||
- name: mcp-context-forge
|
||||
html_url: https://github.com/IBM/mcp-context-forge
|
||||
stars: 2572
|
||||
stars: 2763
|
||||
owner_login: IBM
|
||||
owner_html_url: https://github.com/IBM
|
||||
- name: best-of-web-python
|
||||
html_url: https://github.com/ml-tooling/best-of-web-python
|
||||
stars: 2630
|
||||
owner_login: ml-tooling
|
||||
owner_html_url: https://github.com/ml-tooling
|
||||
- name: fastapi-react
|
||||
html_url: https://github.com/Buuntu/fastapi-react
|
||||
stars: 2451
|
||||
stars: 2464
|
||||
owner_login: Buuntu
|
||||
owner_html_url: https://github.com/Buuntu
|
||||
- name: RasaGPT
|
||||
html_url: https://github.com/paulpierre/RasaGPT
|
||||
stars: 2441
|
||||
owner_login: paulpierre
|
||||
owner_html_url: https://github.com/paulpierre
|
||||
- name: FastAPI-template
|
||||
html_url: https://github.com/s3rius/FastAPI-template
|
||||
stars: 2424
|
||||
stars: 2453
|
||||
owner_login: s3rius
|
||||
owner_html_url: https://github.com/s3rius
|
||||
- name: RasaGPT
|
||||
html_url: https://github.com/paulpierre/RasaGPT
|
||||
stars: 2444
|
||||
owner_login: paulpierre
|
||||
owner_html_url: https://github.com/paulpierre
|
||||
- name: sqladmin
|
||||
html_url: https://github.com/aminalaee/sqladmin
|
||||
stars: 2357
|
||||
stars: 2423
|
||||
owner_login: aminalaee
|
||||
owner_html_url: https://github.com/aminalaee
|
||||
- name: nextpy
|
||||
html_url: https://github.com/dot-agent/nextpy
|
||||
stars: 2324
|
||||
stars: 2325
|
||||
owner_login: dot-agent
|
||||
owner_html_url: https://github.com/dot-agent
|
||||
- name: supabase-py
|
||||
html_url: https://github.com/supabase/supabase-py
|
||||
stars: 2236
|
||||
stars: 2292
|
||||
owner_login: supabase
|
||||
owner_html_url: https://github.com/supabase
|
||||
- name: 30-Days-of-Python
|
||||
html_url: https://github.com/codingforentrepreneurs/30-Days-of-Python
|
||||
stars: 2210
|
||||
stars: 2214
|
||||
owner_login: codingforentrepreneurs
|
||||
owner_html_url: https://github.com/codingforentrepreneurs
|
||||
- name: Yuxi-Know
|
||||
html_url: https://github.com/xerrors/Yuxi-Know
|
||||
stars: 2212
|
||||
owner_login: xerrors
|
||||
owner_html_url: https://github.com/xerrors
|
||||
- name: langserve
|
||||
html_url: https://github.com/langchain-ai/langserve
|
||||
stars: 2171
|
||||
stars: 2191
|
||||
owner_login: langchain-ai
|
||||
owner_html_url: https://github.com/langchain-ai
|
||||
- name: fastapi-utils
|
||||
html_url: https://github.com/fastapiutils/fastapi-utils
|
||||
stars: 2164
|
||||
stars: 2185
|
||||
owner_login: fastapiutils
|
||||
owner_html_url: https://github.com/fastapiutils
|
||||
- name: solara
|
||||
html_url: https://github.com/widgetti/solara
|
||||
stars: 2102
|
||||
stars: 2111
|
||||
owner_login: widgetti
|
||||
owner_html_url: https://github.com/widgetti
|
||||
- name: Yuxi-Know
|
||||
html_url: https://github.com/xerrors/Yuxi-Know
|
||||
stars: 1995
|
||||
owner_login: xerrors
|
||||
owner_html_url: https://github.com/xerrors
|
||||
- name: mangum
|
||||
html_url: https://github.com/Kludex/mangum
|
||||
stars: 1989
|
||||
stars: 2011
|
||||
owner_login: Kludex
|
||||
owner_html_url: https://github.com/Kludex
|
||||
- name: python-week-2022
|
||||
html_url: https://github.com/rochacbruno/python-week-2022
|
||||
stars: 1816
|
||||
owner_login: rochacbruno
|
||||
owner_html_url: https://github.com/rochacbruno
|
||||
- name: agentkit
|
||||
html_url: https://github.com/BCG-X-Official/agentkit
|
||||
stars: 1789
|
||||
stars: 1826
|
||||
owner_login: BCG-X-Official
|
||||
owner_html_url: https://github.com/BCG-X-Official
|
||||
- name: python-week-2022
|
||||
html_url: https://github.com/rochacbruno/python-week-2022
|
||||
stars: 1815
|
||||
owner_login: rochacbruno
|
||||
owner_html_url: https://github.com/rochacbruno
|
||||
- name: manage-fastapi
|
||||
html_url: https://github.com/ycd/manage-fastapi
|
||||
stars: 1780
|
||||
stars: 1787
|
||||
owner_login: ycd
|
||||
owner_html_url: https://github.com/ycd
|
||||
- name: ormar
|
||||
html_url: https://github.com/collerek/ormar
|
||||
stars: 1777
|
||||
stars: 1780
|
||||
owner_login: collerek
|
||||
owner_html_url: https://github.com/collerek
|
||||
- name: vue-fastapi-admin
|
||||
html_url: https://github.com/mizhexiaoxiao/vue-fastapi-admin
|
||||
stars: 1758
|
||||
owner_login: mizhexiaoxiao
|
||||
owner_html_url: https://github.com/mizhexiaoxiao
|
||||
- name: openapi-python-client
|
||||
html_url: https://github.com/openapi-generators/openapi-python-client
|
||||
stars: 1707
|
||||
stars: 1731
|
||||
owner_login: openapi-generators
|
||||
owner_html_url: https://github.com/openapi-generators
|
||||
- name: piccolo
|
||||
html_url: https://github.com/piccolo-orm/piccolo
|
||||
stars: 1695
|
||||
stars: 1711
|
||||
owner_login: piccolo-orm
|
||||
owner_html_url: https://github.com/piccolo-orm
|
||||
- name: vue-fastapi-admin
|
||||
html_url: https://github.com/mizhexiaoxiao/vue-fastapi-admin
|
||||
stars: 1695
|
||||
owner_login: mizhexiaoxiao
|
||||
owner_html_url: https://github.com/mizhexiaoxiao
|
||||
- name: fastapi-cache
|
||||
html_url: https://github.com/long2ice/fastapi-cache
|
||||
stars: 1653
|
||||
stars: 1677
|
||||
owner_login: long2ice
|
||||
owner_html_url: https://github.com/long2ice
|
||||
- name: slowapi
|
||||
html_url: https://github.com/laurentS/slowapi
|
||||
stars: 1669
|
||||
owner_login: laurentS
|
||||
owner_html_url: https://github.com/laurentS
|
||||
- name: langchain-serve
|
||||
html_url: https://github.com/jina-ai/langchain-serve
|
||||
stars: 1635
|
||||
stars: 1632
|
||||
owner_login: jina-ai
|
||||
owner_html_url: https://github.com/jina-ai
|
||||
- name: termpair
|
||||
html_url: https://github.com/cs01/termpair
|
||||
stars: 1624
|
||||
stars: 1621
|
||||
owner_login: cs01
|
||||
owner_html_url: https://github.com/cs01
|
||||
- name: slowapi
|
||||
html_url: https://github.com/laurentS/slowapi
|
||||
stars: 1620
|
||||
owner_login: laurentS
|
||||
owner_html_url: https://github.com/laurentS
|
||||
- name: FastAPI-boilerplate
|
||||
html_url: https://github.com/benavlabs/FastAPI-boilerplate
|
||||
stars: 1596
|
||||
owner_login: benavlabs
|
||||
owner_html_url: https://github.com/benavlabs
|
||||
- name: coronavirus-tracker-api
|
||||
html_url: https://github.com/ExpDev07/coronavirus-tracker-api
|
||||
stars: 1576
|
||||
stars: 1573
|
||||
owner_login: ExpDev07
|
||||
owner_html_url: https://github.com/ExpDev07
|
||||
- name: fastapi-crudrouter
|
||||
html_url: https://github.com/awtkns/fastapi-crudrouter
|
||||
stars: 1546
|
||||
stars: 1553
|
||||
owner_login: awtkns
|
||||
owner_html_url: https://github.com/awtkns
|
||||
- name: FastAPI-boilerplate
|
||||
html_url: https://github.com/benavlabs/FastAPI-boilerplate
|
||||
stars: 1516
|
||||
owner_login: benavlabs
|
||||
owner_html_url: https://github.com/benavlabs
|
||||
- name: awesome-fastapi-projects
|
||||
html_url: https://github.com/Kludex/awesome-fastapi-projects
|
||||
stars: 1481
|
||||
stars: 1485
|
||||
owner_login: Kludex
|
||||
owner_html_url: https://github.com/Kludex
|
||||
- name: fastapi-pagination
|
||||
html_url: https://github.com/uriyyo/fastapi-pagination
|
||||
stars: 1453
|
||||
stars: 1473
|
||||
owner_login: uriyyo
|
||||
owner_html_url: https://github.com/uriyyo
|
||||
- name: bracket
|
||||
html_url: https://github.com/evroon/bracket
|
||||
stars: 1415
|
||||
stars: 1470
|
||||
owner_login: evroon
|
||||
owner_html_url: https://github.com/evroon
|
||||
- name: awesome-python-resources
|
||||
html_url: https://github.com/DjangoEx/awesome-python-resources
|
||||
stars: 1413
|
||||
owner_login: DjangoEx
|
||||
owner_html_url: https://github.com/DjangoEx
|
||||
- name: fastapi-boilerplate
|
||||
html_url: https://github.com/teamhide/fastapi-boilerplate
|
||||
stars: 1406
|
||||
owner_login: teamhide
|
||||
owner_html_url: https://github.com/teamhide
|
||||
- name: budgetml
|
||||
html_url: https://github.com/ebhy/budgetml
|
||||
stars: 1346
|
||||
owner_login: ebhy
|
||||
owner_html_url: https://github.com/ebhy
|
||||
- name: fastapi-amis-admin
|
||||
html_url: https://github.com/amisadmin/fastapi-amis-admin
|
||||
stars: 1342
|
||||
owner_login: amisadmin
|
||||
owner_html_url: https://github.com/amisadmin
|
||||
- name: fastapi-langgraph-agent-production-ready-template
|
||||
html_url: https://github.com/wassim249/fastapi-langgraph-agent-production-ready-template
|
||||
stars: 1334
|
||||
stars: 1456
|
||||
owner_login: wassim249
|
||||
owner_html_url: https://github.com/wassim249
|
||||
- name: fastapi-boilerplate
|
||||
html_url: https://github.com/teamhide/fastapi-boilerplate
|
||||
stars: 1424
|
||||
owner_login: teamhide
|
||||
owner_html_url: https://github.com/teamhide
|
||||
- name: awesome-python-resources
|
||||
html_url: https://github.com/DjangoEx/awesome-python-resources
|
||||
stars: 1420
|
||||
owner_login: DjangoEx
|
||||
owner_html_url: https://github.com/DjangoEx
|
||||
- name: fastapi-amis-admin
|
||||
html_url: https://github.com/amisadmin/fastapi-amis-admin
|
||||
stars: 1363
|
||||
owner_login: amisadmin
|
||||
owner_html_url: https://github.com/amisadmin
|
||||
- name: fastcrud
|
||||
html_url: https://github.com/benavlabs/fastcrud
|
||||
stars: 1362
|
||||
owner_login: benavlabs
|
||||
owner_html_url: https://github.com/benavlabs
|
||||
- name: budgetml
|
||||
html_url: https://github.com/ebhy/budgetml
|
||||
stars: 1345
|
||||
owner_login: ebhy
|
||||
owner_html_url: https://github.com/ebhy
|
||||
- name: fastapi-tutorial
|
||||
html_url: https://github.com/liaogx/fastapi-tutorial
|
||||
stars: 1303
|
||||
stars: 1315
|
||||
owner_login: liaogx
|
||||
owner_html_url: https://github.com/liaogx
|
||||
- name: fastapi_best_architecture
|
||||
html_url: https://github.com/fastapi-practices/fastapi_best_architecture
|
||||
stars: 1276
|
||||
stars: 1311
|
||||
owner_login: fastapi-practices
|
||||
owner_html_url: https://github.com/fastapi-practices
|
||||
- name: fastcrud
|
||||
html_url: https://github.com/benavlabs/fastcrud
|
||||
stars: 1272
|
||||
owner_login: benavlabs
|
||||
owner_html_url: https://github.com/benavlabs
|
||||
- name: fastapi-code-generator
|
||||
html_url: https://github.com/koxudaxi/fastapi-code-generator
|
||||
stars: 1253
|
||||
stars: 1270
|
||||
owner_login: koxudaxi
|
||||
owner_html_url: https://github.com/koxudaxi
|
||||
- name: prometheus-fastapi-instrumentator
|
||||
html_url: https://github.com/trallnag/prometheus-fastapi-instrumentator
|
||||
stars: 1246
|
||||
stars: 1264
|
||||
owner_login: trallnag
|
||||
owner_html_url: https://github.com/trallnag
|
||||
- name: bolt-python
|
||||
html_url: https://github.com/slackapi/bolt-python
|
||||
stars: 1221
|
||||
owner_login: slackapi
|
||||
owner_html_url: https://github.com/slackapi
|
||||
- name: bedrock-chat
|
||||
html_url: https://github.com/aws-samples/bedrock-chat
|
||||
stars: 1220
|
||||
stars: 1243
|
||||
owner_login: aws-samples
|
||||
owner_html_url: https://github.com/aws-samples
|
||||
- name: bolt-python
|
||||
html_url: https://github.com/slackapi/bolt-python
|
||||
stars: 1238
|
||||
owner_login: slackapi
|
||||
owner_html_url: https://github.com/slackapi
|
||||
- name: fastapi_production_template
|
||||
html_url: https://github.com/zhanymkanov/fastapi_production_template
|
||||
stars: 1202
|
||||
stars: 1209
|
||||
owner_login: zhanymkanov
|
||||
owner_html_url: https://github.com/zhanymkanov
|
||||
- name: fastapi-scaff
|
||||
html_url: https://github.com/atpuxiner/fastapi-scaff
|
||||
stars: 1193
|
||||
stars: 1200
|
||||
owner_login: atpuxiner
|
||||
owner_html_url: https://github.com/atpuxiner
|
||||
- name: langchain-extract
|
||||
html_url: https://github.com/langchain-ai/langchain-extract
|
||||
stars: 1164
|
||||
stars: 1173
|
||||
owner_login: langchain-ai
|
||||
owner_html_url: https://github.com/langchain-ai
|
||||
- name: fastapi-alembic-sqlmodel-async
|
||||
html_url: https://github.com/jonra1993/fastapi-alembic-sqlmodel-async
|
||||
stars: 1149
|
||||
stars: 1162
|
||||
owner_login: jonra1993
|
||||
owner_html_url: https://github.com/jonra1993
|
||||
- name: odmantic
|
||||
html_url: https://github.com/art049/odmantic
|
||||
stars: 1133
|
||||
stars: 1137
|
||||
owner_login: art049
|
||||
owner_html_url: https://github.com/art049
|
||||
- name: restish
|
||||
html_url: https://github.com/rest-sh/restish
|
||||
stars: 1122
|
||||
stars: 1129
|
||||
owner_login: rest-sh
|
||||
owner_html_url: https://github.com/rest-sh
|
||||
- name: runhouse
|
||||
html_url: https://github.com/run-house/runhouse
|
||||
stars: 1047
|
||||
- name: kubetorch
|
||||
html_url: https://github.com/run-house/kubetorch
|
||||
stars: 1065
|
||||
owner_login: run-house
|
||||
owner_html_url: https://github.com/run-house
|
||||
- name: flock
|
||||
html_url: https://github.com/Onelevenvy/flock
|
||||
stars: 1027
|
||||
stars: 1039
|
||||
owner_login: Onelevenvy
|
||||
owner_html_url: https://github.com/Onelevenvy
|
||||
- name: authx
|
||||
html_url: https://github.com/yezz123/authx
|
||||
stars: 999
|
||||
stars: 1017
|
||||
owner_login: yezz123
|
||||
owner_html_url: https://github.com/yezz123
|
||||
- name: autollm
|
||||
html_url: https://github.com/viddexa/autollm
|
||||
stars: 999
|
||||
stars: 997
|
||||
owner_login: viddexa
|
||||
owner_html_url: https://github.com/viddexa
|
||||
- name: lanarky
|
||||
html_url: https://github.com/ajndkr/lanarky
|
||||
stars: 995
|
||||
stars: 993
|
||||
owner_login: ajndkr
|
||||
owner_html_url: https://github.com/ajndkr
|
||||
- name: titiler
|
||||
html_url: https://github.com/developmentseed/titiler
|
||||
stars: 952
|
||||
owner_login: developmentseed
|
||||
owner_html_url: https://github.com/developmentseed
|
||||
- name: energy-forecasting
|
||||
html_url: https://github.com/iusztinpaul/energy-forecasting
|
||||
stars: 946
|
||||
owner_login: iusztinpaul
|
||||
owner_html_url: https://github.com/iusztinpaul
|
||||
- name: secure
|
||||
html_url: https://github.com/TypeError/secure
|
||||
stars: 944
|
||||
owner_login: TypeError
|
||||
owner_html_url: https://github.com/TypeError
|
||||
- name: langcorn
|
||||
html_url: https://github.com/msoedov/langcorn
|
||||
stars: 934
|
||||
owner_login: msoedov
|
||||
owner_html_url: https://github.com/msoedov
|
||||
- name: RuoYi-Vue3-FastAPI
|
||||
html_url: https://github.com/insistence/RuoYi-Vue3-FastAPI
|
||||
stars: 930
|
||||
stars: 974
|
||||
owner_login: insistence
|
||||
owner_html_url: https://github.com/insistence
|
||||
- name: aktools
|
||||
html_url: https://github.com/akfamily/aktools
|
||||
stars: 916
|
||||
stars: 972
|
||||
owner_login: akfamily
|
||||
owner_html_url: https://github.com/akfamily
|
||||
- name: titiler
|
||||
html_url: https://github.com/developmentseed/titiler
|
||||
stars: 965
|
||||
owner_login: developmentseed
|
||||
owner_html_url: https://github.com/developmentseed
|
||||
- name: secure
|
||||
html_url: https://github.com/TypeError/secure
|
||||
stars: 953
|
||||
owner_login: TypeError
|
||||
owner_html_url: https://github.com/TypeError
|
||||
- name: energy-forecasting
|
||||
html_url: https://github.com/iusztinpaul/energy-forecasting
|
||||
stars: 949
|
||||
owner_login: iusztinpaul
|
||||
owner_html_url: https://github.com/iusztinpaul
|
||||
- name: every-pdf
|
||||
html_url: https://github.com/DDULDDUCK/every-pdf
|
||||
stars: 907
|
||||
stars: 942
|
||||
owner_login: DDULDDUCK
|
||||
owner_html_url: https://github.com/DDULDDUCK
|
||||
- name: marker-api
|
||||
html_url: https://github.com/adithya-s-k/marker-api
|
||||
stars: 903
|
||||
owner_login: adithya-s-k
|
||||
owner_html_url: https://github.com/adithya-s-k
|
||||
- name: langcorn
|
||||
html_url: https://github.com/msoedov/langcorn
|
||||
stars: 933
|
||||
owner_login: msoedov
|
||||
owner_html_url: https://github.com/msoedov
|
||||
- name: fastapi-observability
|
||||
html_url: https://github.com/blueswen/fastapi-observability
|
||||
stars: 902
|
||||
stars: 923
|
||||
owner_login: blueswen
|
||||
owner_html_url: https://github.com/blueswen
|
||||
- name: fastapi-do-zero
|
||||
html_url: https://github.com/dunossauro/fastapi-do-zero
|
||||
stars: 900
|
||||
owner_login: dunossauro
|
||||
owner_html_url: https://github.com/dunossauro
|
||||
|
||||
@@ -776,7 +776,7 @@ pablocm83:
|
||||
d2a-raudenaerde:
|
||||
login: d2a-raudenaerde
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5213150?v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/5213150?u=e6d0ef65c571c7e544fc1c7ec151c7c0a72fb6bb&v=4
|
||||
url: https://github.com/d2a-raudenaerde
|
||||
valentinDruzhinin:
|
||||
login: valentinDruzhinin
|
||||
@@ -1206,7 +1206,7 @@ akagaeng:
|
||||
phamquanganh31101998:
|
||||
login: phamquanganh31101998
|
||||
count: 3
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43257497?u=36fa4ee689415d869a98453083a7c4213d2136ee&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/43257497?u=6b3419ea9e318c356c42a973fb947682590bd8d3&v=4
|
||||
url: https://github.com/phamquanganh31101998
|
||||
peebbv6364:
|
||||
login: peebbv6364
|
||||
@@ -1806,7 +1806,7 @@ MrL8199:
|
||||
ivintoiu:
|
||||
login: ivintoiu
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1853336?u=5e3d0977f44661fb9712fa297cc8f7608ea6ce48&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1853336?u=b537c905ad08b69993de8796fb235c8d4d47f039&v=4
|
||||
url: https://github.com/ivintoiu
|
||||
TechnoService2:
|
||||
login: TechnoService2
|
||||
@@ -1841,7 +1841,7 @@ NavesSapnis:
|
||||
eqsdxr:
|
||||
login: eqsdxr
|
||||
count: 2
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=58fddf77ed76966eaa8c73eea9bea4bb0c53b673&v=4
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/157279130?u=d7aaffb29f542b647cf0f6b0e05722490863658a&v=4
|
||||
url: https://github.com/eqsdxr
|
||||
syedasamina56:
|
||||
login: syedasamina56
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
nilslindemann:
|
||||
login: nilslindemann
|
||||
count: 122
|
||||
count: 124
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/6892179?u=1dca6a22195d6cd1ab20737c0e19a4c55d639472&v=4
|
||||
url: https://github.com/nilslindemann
|
||||
jaystone776:
|
||||
@@ -103,6 +103,11 @@ pablocm83:
|
||||
count: 8
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/28315068?u=3310fbb05bb8bfc50d2c48b6cb64ac9ee4a14549&v=4
|
||||
url: https://github.com/pablocm83
|
||||
tiangolo:
|
||||
login: tiangolo
|
||||
count: 7
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
|
||||
url: https://github.com/tiangolo
|
||||
ptt3199:
|
||||
login: ptt3199
|
||||
count: 7
|
||||
@@ -118,11 +123,6 @@ batlopes:
|
||||
count: 6
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/33462923?u=0fb3d7acb316764616f11e4947faf080e49ad8d9&v=4
|
||||
url: https://github.com/batlopes
|
||||
tiangolo:
|
||||
login: tiangolo
|
||||
count: 6
|
||||
avatarUrl: https://avatars.githubusercontent.com/u/1326112?u=cb5d06e73a9e1998141b1641aa88e443c6717651&v=4
|
||||
url: https://github.com/tiangolo
|
||||
lucasbalieiro:
|
||||
login: lucasbalieiro
|
||||
count: 6
|
||||
|
||||
@@ -7,6 +7,39 @@ hide:
|
||||
|
||||
## Latest Changes
|
||||
|
||||
## 0.121.0
|
||||
|
||||
### Features
|
||||
|
||||
* ✨ Add support for dependencies with scopes, support `scope="request"` for dependencies with `yield` that exit before the response is sent. PR [#14262](https://github.com/fastapi/fastapi/pull/14262) by [@tiangolo](https://github.com/tiangolo).
|
||||
* New docs: [Dependencies with `yield` - Early exit and `scope`](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#early-exit-and-scope).
|
||||
|
||||
### Internal
|
||||
|
||||
* 👥 Update FastAPI People - Contributors and Translators. PR [#14273](https://github.com/fastapi/fastapi/pull/14273) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👥 Update FastAPI People - Sponsors. PR [#14274](https://github.com/fastapi/fastapi/pull/14274) by [@tiangolo](https://github.com/tiangolo).
|
||||
* 👥 Update FastAPI GitHub topic repositories. PR [#14280](https://github.com/fastapi/fastapi/pull/14280) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ⬆ Bump mkdocs-macros-plugin from 1.4.0 to 1.4.1. PR [#14277](https://github.com/fastapi/fastapi/pull/14277) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
* ⬆ Bump mkdocstrings[python] from 0.26.1 to 0.30.1. PR [#14279](https://github.com/fastapi/fastapi/pull/14279) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
||||
|
||||
## 0.120.4
|
||||
|
||||
### Fixes
|
||||
|
||||
* 🐛 Fix security schemes in OpenAPI when added at the top level app. PR [#14266](https://github.com/fastapi/fastapi/pull/14266) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
|
||||
## 0.120.3
|
||||
|
||||
### Refactors
|
||||
|
||||
* ♻️ Reduce internal cyclic recursion in dependencies, from 2 functions calling each other to 1 calling itself. PR [#14256](https://github.com/fastapi/fastapi/pull/14256) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ♻️ Refactor internals of dependencies, simplify code and remove `get_param_sub_dependant`. PR [#14255](https://github.com/fastapi/fastapi/pull/14255) by [@tiangolo](https://github.com/tiangolo).
|
||||
* ♻️ Refactor internals of dependencies, simplify using dataclasses. PR [#14254](https://github.com/fastapi/fastapi/pull/14254) by [@tiangolo](https://github.com/tiangolo).
|
||||
|
||||
### Docs
|
||||
|
||||
* 📝 Update note for untranslated pages. PR [#14257](https://github.com/fastapi/fastapi/pull/14257) by [@YuriiMotov](https://github.com/YuriiMotov).
|
||||
|
||||
## 0.120.2
|
||||
|
||||
### Fixes
|
||||
|
||||
@@ -184,6 +184,51 @@ If you raise any exception in the code from the *path operation function*, it wi
|
||||
|
||||
///
|
||||
|
||||
## Early exit and `scope` { #early-exit-and-scope }
|
||||
|
||||
Normally the exit code of dependencies with `yield` is executed **after the response** is sent to the client.
|
||||
|
||||
But if you know that you won't need to use the dependency after returning from the *path operation function*, you can use `Depends(scope="function")` to tell FastAPI that it should close the dependency after the *path operation function* returns, but **before** the **response is sent**.
|
||||
|
||||
{* ../../docs_src/dependencies/tutorial008e_an_py39.py hl[12,16] *}
|
||||
|
||||
`Depends()` receives a `scope` parameter that can be:
|
||||
|
||||
* `"function"`: start the dependency before the *path operation function* that handles the request, end the dependency after the *path operation function* ends, but **before** the response is sent back to the client. So, the dependency function will be executed **around** the *path operation **function***.
|
||||
* `"request"`: start the dependency before the *path operation function* that handles the request (similar to when using `"function"`), but end **after** the response is sent back to the client. So, the dependency function will be executed **around** the **request** and response cycle.
|
||||
|
||||
If not specified and the dependency has `yield`, it will have a `scope` of `"request"` by default.
|
||||
|
||||
### `scope` for sub-dependencies { #scope-for-sub-dependencies }
|
||||
|
||||
When you declare a dependency with a `scope="request"` (the default), any sub-dependency needs to also have a `scope` of `"request"`.
|
||||
|
||||
But a dependency with `scope` of `"function"` can have dependencies with `scope` of `"function"` and `scope` of `"request"`.
|
||||
|
||||
This is because any dependency needs to be able to run its exit code before the sub-dependencies, as it might need to still use them during its exit code.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
|
||||
participant client as Client
|
||||
participant dep_req as Dep scope="request"
|
||||
participant dep_func as Dep scope="function"
|
||||
participant operation as Path Operation
|
||||
|
||||
client ->> dep_req: Start request
|
||||
Note over dep_req: Run code up to yield
|
||||
dep_req ->> dep_func: Pass dependency
|
||||
Note over dep_func: Run code up to yield
|
||||
dep_func ->> operation: Run path operation with dependency
|
||||
operation ->> dep_func: Return from path operation
|
||||
Note over dep_func: Run code after yield
|
||||
Note over dep_func: ✅ Dependency closed
|
||||
dep_func ->> client: Send response to client
|
||||
Note over client: Response sent
|
||||
Note over dep_req: Run code after yield
|
||||
Note over dep_req: ✅ Dependency closed
|
||||
```
|
||||
|
||||
## Dependencies with `yield`, `HTTPException`, `except` and Background Tasks { #dependencies-with-yield-httpexception-except-and-background-tasks }
|
||||
|
||||
Dependencies with `yield` have evolved over time to cover different use cases and fix some issues.
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/// warning
|
||||
|
||||
The current page still doesn't have a translation for this language.
|
||||
This page hasn’t been translated into your language yet. 🌍
|
||||
|
||||
But you can help translating it: [Contributing](https://fastapi.tiangolo.com/contributing/){.internal-link target=_blank}.
|
||||
We’re currently switching to an automated translation system 🤖, which will help keep all translations complete and up to date.
|
||||
|
||||
Learn more: [Contributing – Translations](https://fastapi.tiangolo.com/contributing/#translations){.internal-link target=_blank}
|
||||
|
||||
///
|
||||
|
||||
15
docs_src/dependencies/tutorial008e.py
Normal file
15
docs_src/dependencies/tutorial008e.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
def get_username():
|
||||
try:
|
||||
yield "Rick"
|
||||
finally:
|
||||
print("Cleanup up before response is sent")
|
||||
|
||||
|
||||
@app.get("/users/me")
|
||||
def get_user_me(username: str = Depends(get_username, scope="function")):
|
||||
return username
|
||||
16
docs_src/dependencies/tutorial008e_an.py
Normal file
16
docs_src/dependencies/tutorial008e_an.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from fastapi import Depends, FastAPI
|
||||
from typing_extensions import Annotated
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
def get_username():
|
||||
try:
|
||||
yield "Rick"
|
||||
finally:
|
||||
print("Cleanup up before response is sent")
|
||||
|
||||
|
||||
@app.get("/users/me")
|
||||
def get_user_me(username: Annotated[str, Depends(get_username, scope="function")]):
|
||||
return username
|
||||
17
docs_src/dependencies/tutorial008e_an_py39.py
Normal file
17
docs_src/dependencies/tutorial008e_an_py39.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
def get_username():
|
||||
try:
|
||||
yield "Rick"
|
||||
finally:
|
||||
print("Cleanup up before response is sent")
|
||||
|
||||
|
||||
@app.get("/users/me")
|
||||
def get_user_me(username: Annotated[str, Depends(get_username, scope="function")]):
|
||||
return username
|
||||
@@ -1,6 +1,6 @@
|
||||
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
|
||||
|
||||
__version__ = "0.120.2"
|
||||
__version__ = "0.121.0"
|
||||
|
||||
from starlette import status as status
|
||||
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
import inspect
|
||||
import sys
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Callable, List, Optional, Sequence, Tuple
|
||||
from functools import cached_property
|
||||
from typing import Any, Callable, List, Optional, Sequence, Union
|
||||
|
||||
from fastapi._compat import ModelField
|
||||
from fastapi.security.base import SecurityBase
|
||||
from fastapi.types import DependencyCacheKey
|
||||
from typing_extensions import Literal
|
||||
|
||||
if sys.version_info >= (3, 13): # pragma: no cover
|
||||
from inspect import iscoroutinefunction
|
||||
else: # pragma: no cover
|
||||
from asyncio import iscoroutinefunction
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -31,7 +41,43 @@ class Dependant:
|
||||
security_scopes: Optional[List[str]] = None
|
||||
use_cache: bool = True
|
||||
path: Optional[str] = None
|
||||
cache_key: Tuple[Optional[Callable[..., Any]], Tuple[str, ...]] = field(init=False)
|
||||
scope: Union[Literal["function", "request"], None] = None
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
self.cache_key = (self.call, tuple(sorted(set(self.security_scopes or []))))
|
||||
@cached_property
|
||||
def cache_key(self) -> DependencyCacheKey:
|
||||
return (
|
||||
self.call,
|
||||
tuple(sorted(set(self.security_scopes or []))),
|
||||
self.computed_scope or "",
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def is_gen_callable(self) -> bool:
|
||||
if inspect.isgeneratorfunction(self.call):
|
||||
return True
|
||||
dunder_call = getattr(self.call, "__call__", None) # noqa: B004
|
||||
return inspect.isgeneratorfunction(dunder_call)
|
||||
|
||||
@cached_property
|
||||
def is_async_gen_callable(self) -> bool:
|
||||
if inspect.isasyncgenfunction(self.call):
|
||||
return True
|
||||
dunder_call = getattr(self.call, "__call__", None) # noqa: B004
|
||||
return inspect.isasyncgenfunction(dunder_call)
|
||||
|
||||
@cached_property
|
||||
def is_coroutine_callable(self) -> bool:
|
||||
if inspect.isroutine(self.call):
|
||||
return iscoroutinefunction(self.call)
|
||||
if inspect.isclass(self.call):
|
||||
return False
|
||||
dunder_call = getattr(self.call, "__call__", None) # noqa: B004
|
||||
return iscoroutinefunction(dunder_call)
|
||||
|
||||
@cached_property
|
||||
def computed_scope(self) -> Union[str, None]:
|
||||
if self.scope:
|
||||
return self.scope
|
||||
if self.is_gen_callable or self.is_async_gen_callable:
|
||||
return "request"
|
||||
return None
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import inspect
|
||||
import sys
|
||||
from contextlib import AsyncExitStack, contextmanager
|
||||
from copy import copy, deepcopy
|
||||
from dataclasses import dataclass
|
||||
@@ -55,10 +54,12 @@ from fastapi.concurrency import (
|
||||
contextmanager_in_threadpool,
|
||||
)
|
||||
from fastapi.dependencies.models import Dependant, SecurityRequirement
|
||||
from fastapi.exceptions import DependencyScopeError
|
||||
from fastapi.logger import logger
|
||||
from fastapi.security.base import SecurityBase
|
||||
from fastapi.security.oauth2 import OAuth2, SecurityScopes
|
||||
from fastapi.security.open_id_connect_url import OpenIdConnect
|
||||
from fastapi.types import DependencyCacheKey
|
||||
from fastapi.utils import create_model_field, get_path_param_names
|
||||
from pydantic import BaseModel
|
||||
from pydantic.fields import FieldInfo
|
||||
@@ -74,15 +75,10 @@ from starlette.datastructures import (
|
||||
from starlette.requests import HTTPConnection, Request
|
||||
from starlette.responses import Response
|
||||
from starlette.websockets import WebSocket
|
||||
from typing_extensions import Annotated, get_args, get_origin
|
||||
from typing_extensions import Annotated, Literal, get_args, get_origin
|
||||
|
||||
from .. import temp_pydantic_v1_params
|
||||
|
||||
if sys.version_info >= (3, 13): # pragma: no cover
|
||||
from inspect import iscoroutinefunction
|
||||
else: # pragma: no cover
|
||||
from asyncio import iscoroutinefunction
|
||||
|
||||
multipart_not_installed_error = (
|
||||
'Form data requires "python-multipart" to be installed. \n'
|
||||
'You can install "python-multipart" with: \n\n'
|
||||
@@ -125,70 +121,23 @@ def ensure_multipart_is_installed() -> None:
|
||||
raise RuntimeError(multipart_not_installed_error) from None
|
||||
|
||||
|
||||
def get_param_sub_dependant(
|
||||
*,
|
||||
param_name: str,
|
||||
depends: params.Depends,
|
||||
path: str,
|
||||
security_scopes: Optional[List[str]] = None,
|
||||
) -> Dependant:
|
||||
assert depends.dependency
|
||||
return get_sub_dependant(
|
||||
depends=depends,
|
||||
dependency=depends.dependency,
|
||||
path=path,
|
||||
name=param_name,
|
||||
security_scopes=security_scopes,
|
||||
)
|
||||
|
||||
|
||||
def get_parameterless_sub_dependant(*, depends: params.Depends, path: str) -> Dependant:
|
||||
assert callable(depends.dependency), (
|
||||
"A parameter-less dependency must have a callable dependency"
|
||||
)
|
||||
return get_sub_dependant(depends=depends, dependency=depends.dependency, path=path)
|
||||
|
||||
|
||||
def get_sub_dependant(
|
||||
*,
|
||||
depends: params.Depends,
|
||||
dependency: Callable[..., Any],
|
||||
path: str,
|
||||
name: Optional[str] = None,
|
||||
security_scopes: Optional[List[str]] = None,
|
||||
) -> Dependant:
|
||||
security_requirement = None
|
||||
security_scopes = security_scopes or []
|
||||
if isinstance(depends, params.Security):
|
||||
dependency_scopes = depends.scopes
|
||||
security_scopes.extend(dependency_scopes)
|
||||
if isinstance(dependency, SecurityBase):
|
||||
use_scopes: List[str] = []
|
||||
if isinstance(dependency, (OAuth2, OpenIdConnect)):
|
||||
use_scopes = security_scopes
|
||||
security_requirement = SecurityRequirement(
|
||||
security_scheme=dependency, scopes=use_scopes
|
||||
)
|
||||
sub_dependant = get_dependant(
|
||||
path=path,
|
||||
call=dependency,
|
||||
name=name,
|
||||
security_scopes=security_scopes,
|
||||
use_cache=depends.use_cache,
|
||||
use_security_scopes: List[str] = []
|
||||
if isinstance(depends, params.Security) and depends.scopes:
|
||||
use_security_scopes.extend(depends.scopes)
|
||||
return get_dependant(
|
||||
path=path, call=depends.dependency, security_scopes=use_security_scopes
|
||||
)
|
||||
if security_requirement:
|
||||
sub_dependant.security_requirements.append(security_requirement)
|
||||
return sub_dependant
|
||||
|
||||
|
||||
CacheKey = Tuple[Optional[Callable[..., Any]], Tuple[str, ...]]
|
||||
|
||||
|
||||
def get_flat_dependant(
|
||||
dependant: Dependant,
|
||||
*,
|
||||
skip_repeats: bool = False,
|
||||
visited: Optional[List[CacheKey]] = None,
|
||||
visited: Optional[List[DependencyCacheKey]] = None,
|
||||
) -> Dependant:
|
||||
if visited is None:
|
||||
visited = []
|
||||
@@ -281,17 +230,27 @@ def get_dependant(
|
||||
name: Optional[str] = None,
|
||||
security_scopes: Optional[List[str]] = None,
|
||||
use_cache: bool = True,
|
||||
scope: Union[Literal["function", "request"], None] = None,
|
||||
) -> Dependant:
|
||||
path_param_names = get_path_param_names(path)
|
||||
endpoint_signature = get_typed_signature(call)
|
||||
signature_params = endpoint_signature.parameters
|
||||
dependant = Dependant(
|
||||
call=call,
|
||||
name=name,
|
||||
path=path,
|
||||
security_scopes=security_scopes,
|
||||
use_cache=use_cache,
|
||||
scope=scope,
|
||||
)
|
||||
path_param_names = get_path_param_names(path)
|
||||
endpoint_signature = get_typed_signature(call)
|
||||
signature_params = endpoint_signature.parameters
|
||||
if isinstance(call, SecurityBase):
|
||||
use_scopes: List[str] = []
|
||||
if isinstance(call, (OAuth2, OpenIdConnect)):
|
||||
use_scopes = security_scopes or use_scopes
|
||||
security_requirement = SecurityRequirement(
|
||||
security_scheme=call, scopes=use_scopes
|
||||
)
|
||||
dependant.security_requirements.append(security_requirement)
|
||||
for param_name, param in signature_params.items():
|
||||
is_path_param = param_name in path_param_names
|
||||
param_details = analyze_param(
|
||||
@@ -301,11 +260,28 @@ def get_dependant(
|
||||
is_path_param=is_path_param,
|
||||
)
|
||||
if param_details.depends is not None:
|
||||
sub_dependant = get_param_sub_dependant(
|
||||
param_name=param_name,
|
||||
depends=param_details.depends,
|
||||
assert param_details.depends.dependency
|
||||
if (
|
||||
(dependant.is_gen_callable or dependant.is_async_gen_callable)
|
||||
and dependant.computed_scope == "request"
|
||||
and param_details.depends.scope == "function"
|
||||
):
|
||||
assert dependant.call
|
||||
raise DependencyScopeError(
|
||||
f'The dependency "{dependant.call.__name__}" has a scope of '
|
||||
'"request", it cannot depend on dependencies with scope "function".'
|
||||
)
|
||||
use_security_scopes = security_scopes or []
|
||||
if isinstance(param_details.depends, params.Security):
|
||||
if param_details.depends.scopes:
|
||||
use_security_scopes.extend(param_details.depends.scopes)
|
||||
sub_dependant = get_dependant(
|
||||
path=path,
|
||||
security_scopes=security_scopes,
|
||||
call=param_details.depends.dependency,
|
||||
name=param_name,
|
||||
security_scopes=use_security_scopes,
|
||||
use_cache=param_details.depends.use_cache,
|
||||
scope=param_details.depends.scope,
|
||||
)
|
||||
dependant.dependencies.append(sub_dependant)
|
||||
continue
|
||||
@@ -562,36 +538,14 @@ def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None:
|
||||
dependant.cookie_params.append(field)
|
||||
|
||||
|
||||
def is_coroutine_callable(call: Callable[..., Any]) -> bool:
|
||||
if inspect.isroutine(call):
|
||||
return iscoroutinefunction(call)
|
||||
if inspect.isclass(call):
|
||||
return False
|
||||
dunder_call = getattr(call, "__call__", None) # noqa: B004
|
||||
return iscoroutinefunction(dunder_call)
|
||||
|
||||
|
||||
def is_async_gen_callable(call: Callable[..., Any]) -> bool:
|
||||
if inspect.isasyncgenfunction(call):
|
||||
return True
|
||||
dunder_call = getattr(call, "__call__", None) # noqa: B004
|
||||
return inspect.isasyncgenfunction(dunder_call)
|
||||
|
||||
|
||||
def is_gen_callable(call: Callable[..., Any]) -> bool:
|
||||
if inspect.isgeneratorfunction(call):
|
||||
return True
|
||||
dunder_call = getattr(call, "__call__", None) # noqa: B004
|
||||
return inspect.isgeneratorfunction(dunder_call)
|
||||
|
||||
|
||||
async def solve_generator(
|
||||
*, call: Callable[..., Any], stack: AsyncExitStack, sub_values: Dict[str, Any]
|
||||
async def _solve_generator(
|
||||
*, dependant: Dependant, stack: AsyncExitStack, sub_values: Dict[str, Any]
|
||||
) -> Any:
|
||||
if is_gen_callable(call):
|
||||
cm = contextmanager_in_threadpool(contextmanager(call)(**sub_values))
|
||||
elif is_async_gen_callable(call):
|
||||
cm = asynccontextmanager(call)(**sub_values)
|
||||
assert dependant.call
|
||||
if dependant.is_gen_callable:
|
||||
cm = contextmanager_in_threadpool(contextmanager(dependant.call)(**sub_values))
|
||||
elif dependant.is_async_gen_callable:
|
||||
cm = asynccontextmanager(dependant.call)(**sub_values)
|
||||
return await stack.enter_async_context(cm)
|
||||
|
||||
|
||||
@@ -601,7 +555,7 @@ class SolvedDependency:
|
||||
errors: List[Any]
|
||||
background_tasks: Optional[StarletteBackgroundTasks]
|
||||
response: Response
|
||||
dependency_cache: Dict[Tuple[Callable[..., Any], Tuple[str]], Any]
|
||||
dependency_cache: Dict[DependencyCacheKey, Any]
|
||||
|
||||
|
||||
async def solve_dependencies(
|
||||
@@ -612,10 +566,20 @@ async def solve_dependencies(
|
||||
background_tasks: Optional[StarletteBackgroundTasks] = None,
|
||||
response: Optional[Response] = None,
|
||||
dependency_overrides_provider: Optional[Any] = None,
|
||||
dependency_cache: Optional[Dict[Tuple[Callable[..., Any], Tuple[str]], Any]] = None,
|
||||
dependency_cache: Optional[Dict[DependencyCacheKey, Any]] = None,
|
||||
# TODO: remove this parameter later, no longer used, not removing it yet as some
|
||||
# people might be monkey patching this function (although that's not supported)
|
||||
async_exit_stack: AsyncExitStack,
|
||||
embed_body_fields: bool,
|
||||
) -> SolvedDependency:
|
||||
request_astack = request.scope.get("fastapi_inner_astack")
|
||||
assert isinstance(request_astack, AsyncExitStack), (
|
||||
"fastapi_inner_astack not found in request scope"
|
||||
)
|
||||
function_astack = request.scope.get("fastapi_function_astack")
|
||||
assert isinstance(function_astack, AsyncExitStack), (
|
||||
"fastapi_function_astack not found in request scope"
|
||||
)
|
||||
values: Dict[str, Any] = {}
|
||||
errors: List[Any] = []
|
||||
if response is None:
|
||||
@@ -624,12 +588,8 @@ async def solve_dependencies(
|
||||
response.status_code = None # type: ignore
|
||||
if dependency_cache is None:
|
||||
dependency_cache = {}
|
||||
sub_dependant: Dependant
|
||||
for sub_dependant in dependant.dependencies:
|
||||
sub_dependant.call = cast(Callable[..., Any], sub_dependant.call)
|
||||
sub_dependant.cache_key = cast(
|
||||
Tuple[Callable[..., Any], Tuple[str]], sub_dependant.cache_key
|
||||
)
|
||||
call = sub_dependant.call
|
||||
use_sub_dependant = sub_dependant
|
||||
if (
|
||||
@@ -646,6 +606,7 @@ async def solve_dependencies(
|
||||
call=call,
|
||||
name=sub_dependant.name,
|
||||
security_scopes=sub_dependant.security_scopes,
|
||||
scope=sub_dependant.scope,
|
||||
)
|
||||
|
||||
solved_result = await solve_dependencies(
|
||||
@@ -665,11 +626,18 @@ async def solve_dependencies(
|
||||
continue
|
||||
if sub_dependant.use_cache and sub_dependant.cache_key in dependency_cache:
|
||||
solved = dependency_cache[sub_dependant.cache_key]
|
||||
elif is_gen_callable(call) or is_async_gen_callable(call):
|
||||
solved = await solve_generator(
|
||||
call=call, stack=async_exit_stack, sub_values=solved_result.values
|
||||
elif (
|
||||
use_sub_dependant.is_gen_callable or use_sub_dependant.is_async_gen_callable
|
||||
):
|
||||
use_astack = request_astack
|
||||
if sub_dependant.scope == "function":
|
||||
use_astack = function_astack
|
||||
solved = await _solve_generator(
|
||||
dependant=use_sub_dependant,
|
||||
stack=use_astack,
|
||||
sub_values=solved_result.values,
|
||||
)
|
||||
elif is_coroutine_callable(call):
|
||||
elif use_sub_dependant.is_coroutine_callable:
|
||||
solved = await call(**solved_result.values)
|
||||
else:
|
||||
solved = await run_in_threadpool(call, **solved_result.values)
|
||||
|
||||
@@ -147,6 +147,13 @@ class FastAPIError(RuntimeError):
|
||||
"""
|
||||
|
||||
|
||||
class DependencyScopeError(FastAPIError):
|
||||
"""
|
||||
A dependency declared that it depends on another dependency with an invalid
|
||||
(narrower) scope.
|
||||
"""
|
||||
|
||||
|
||||
class ValidationException(Exception):
|
||||
def __init__(self, errors: Sequence[Any]) -> None:
|
||||
self._errors = errors
|
||||
|
||||
@@ -4,7 +4,7 @@ from annotated_doc import Doc
|
||||
from fastapi import params
|
||||
from fastapi._compat import Undefined
|
||||
from fastapi.openapi.models import Example
|
||||
from typing_extensions import Annotated, deprecated
|
||||
from typing_extensions import Annotated, Literal, deprecated
|
||||
|
||||
_Unset: Any = Undefined
|
||||
|
||||
@@ -2245,6 +2245,26 @@ def Depends( # noqa: N802
|
||||
"""
|
||||
),
|
||||
] = True,
|
||||
scope: Annotated[
|
||||
Union[Literal["function", "request"], None],
|
||||
Doc(
|
||||
"""
|
||||
Mainly for dependencies with `yield`, define when the dependency function
|
||||
should start (the code before `yield`) and when it should end (the code
|
||||
after `yield`).
|
||||
|
||||
* `"function"`: start the dependency before the *path operation function*
|
||||
that handles the request, end the dependency after the *path operation
|
||||
function* ends, but **before** the response is sent back to the client.
|
||||
So, the dependency function will be executed **around** the *path operation
|
||||
**function***.
|
||||
* `"request"`: start the dependency before the *path operation function*
|
||||
that handles the request (similar to when using `"function"`), but end
|
||||
**after** the response is sent back to the client. So, the dependency
|
||||
function will be executed **around** the **request** and response cycle.
|
||||
"""
|
||||
),
|
||||
] = None,
|
||||
) -> Any:
|
||||
"""
|
||||
Declare a FastAPI dependency.
|
||||
@@ -2275,7 +2295,7 @@ def Depends( # noqa: N802
|
||||
return commons
|
||||
```
|
||||
"""
|
||||
return params.Depends(dependency=dependency, use_cache=use_cache)
|
||||
return params.Depends(dependency=dependency, use_cache=use_cache, scope=scope)
|
||||
|
||||
|
||||
def Security( # noqa: N802
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import warnings
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
from typing import Any, Callable, Dict, List, Optional, Sequence, Union
|
||||
|
||||
from fastapi.openapi.models import Example
|
||||
from pydantic.fields import FieldInfo
|
||||
from typing_extensions import Annotated, deprecated
|
||||
from typing_extensions import Annotated, Literal, deprecated
|
||||
|
||||
from ._compat import (
|
||||
PYDANTIC_V2,
|
||||
@@ -761,26 +762,13 @@ class File(Form): # type: ignore[misc]
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Depends:
|
||||
def __init__(
|
||||
self, dependency: Optional[Callable[..., Any]] = None, *, use_cache: bool = True
|
||||
):
|
||||
self.dependency = dependency
|
||||
self.use_cache = use_cache
|
||||
|
||||
def __repr__(self) -> str:
|
||||
attr = getattr(self.dependency, "__name__", type(self.dependency).__name__)
|
||||
cache = "" if self.use_cache else ", use_cache=False"
|
||||
return f"{self.__class__.__name__}({attr}{cache})"
|
||||
dependency: Optional[Callable[..., Any]] = None
|
||||
use_cache: bool = True
|
||||
scope: Union[Literal["function", "request"], None] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Security(Depends):
|
||||
def __init__(
|
||||
self,
|
||||
dependency: Optional[Callable[..., Any]] = None,
|
||||
*,
|
||||
scopes: Optional[Sequence[str]] = None,
|
||||
use_cache: bool = True,
|
||||
):
|
||||
super().__init__(dependency=dependency, use_cache=use_cache)
|
||||
self.scopes = scopes or []
|
||||
scopes: Optional[Sequence[str]] = None
|
||||
|
||||
@@ -104,10 +104,11 @@ def request_response(
|
||||
async def app(scope: Scope, receive: Receive, send: Send) -> None:
|
||||
# Starts customization
|
||||
response_awaited = False
|
||||
async with AsyncExitStack() as stack:
|
||||
scope["fastapi_inner_astack"] = stack
|
||||
# Same as in Starlette
|
||||
response = await f(request)
|
||||
async with AsyncExitStack() as request_stack:
|
||||
scope["fastapi_inner_astack"] = request_stack
|
||||
async with AsyncExitStack() as function_stack:
|
||||
scope["fastapi_function_astack"] = function_stack
|
||||
response = await f(request)
|
||||
await response(scope, receive, send)
|
||||
# Continues customization
|
||||
response_awaited = True
|
||||
@@ -140,11 +141,11 @@ def websocket_session(
|
||||
session = WebSocket(scope, receive=receive, send=send)
|
||||
|
||||
async def app(scope: Scope, receive: Receive, send: Send) -> None:
|
||||
# Starts customization
|
||||
async with AsyncExitStack() as stack:
|
||||
scope["fastapi_inner_astack"] = stack
|
||||
# Same as in Starlette
|
||||
await func(session)
|
||||
async with AsyncExitStack() as request_stack:
|
||||
scope["fastapi_inner_astack"] = request_stack
|
||||
async with AsyncExitStack() as function_stack:
|
||||
scope["fastapi_function_astack"] = function_stack
|
||||
await func(session)
|
||||
|
||||
# Same as in Starlette
|
||||
await wrap_app_handling_exceptions(app, session)(scope, receive, send)
|
||||
@@ -479,7 +480,9 @@ class APIWebSocketRoute(routing.WebSocketRoute):
|
||||
self.name = get_name(endpoint) if name is None else name
|
||||
self.dependencies = list(dependencies or [])
|
||||
self.path_regex, self.path_format, self.param_convertors = compile_path(path)
|
||||
self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
|
||||
self.dependant = get_dependant(
|
||||
path=self.path_format, call=self.endpoint, scope="function"
|
||||
)
|
||||
for depends in self.dependencies[::-1]:
|
||||
self.dependant.dependencies.insert(
|
||||
0,
|
||||
@@ -630,7 +633,9 @@ class APIRoute(routing.Route):
|
||||
self.response_fields = {}
|
||||
|
||||
assert callable(endpoint), "An endpoint must be a callable"
|
||||
self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
|
||||
self.dependant = get_dependant(
|
||||
path=self.path_format, call=self.endpoint, scope="function"
|
||||
)
|
||||
for depends in self.dependencies[::-1]:
|
||||
self.dependant.dependencies.insert(
|
||||
0,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import types
|
||||
from enum import Enum
|
||||
from typing import Any, Callable, Dict, Set, Type, TypeVar, Union
|
||||
from typing import Any, Callable, Dict, Optional, Set, Tuple, Type, TypeVar, Union
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -8,3 +8,4 @@ DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any])
|
||||
UnionType = getattr(types, "UnionType", Union)
|
||||
ModelNameMap = Dict[Union[Type[BaseModel], Type[Enum]], str]
|
||||
IncEx = Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any]]
|
||||
DependencyCacheKey = Tuple[Optional[Callable[..., Any]], Tuple[str, ...], str]
|
||||
|
||||
@@ -11,9 +11,9 @@ jieba==0.42.1
|
||||
pillow==11.3.0
|
||||
# For image processing by Material for MkDocs
|
||||
cairosvg==2.8.2
|
||||
mkdocstrings[python]==0.26.1
|
||||
mkdocstrings[python]==0.30.1
|
||||
griffe-typingdoc==0.3.0
|
||||
# For griffe, it formats with black
|
||||
black==25.1.0
|
||||
mkdocs-macros-plugin==1.4.0
|
||||
mkdocs-macros-plugin==1.4.1
|
||||
markdown-include-variants==0.0.5
|
||||
|
||||
78
tests/test_dependency_paramless.py
Normal file
78
tests/test_dependency_paramless.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from typing import Union
|
||||
|
||||
from fastapi import FastAPI, HTTPException, Security
|
||||
from fastapi.security import (
|
||||
OAuth2PasswordBearer,
|
||||
SecurityScopes,
|
||||
)
|
||||
from fastapi.testclient import TestClient
|
||||
from typing_extensions import Annotated
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
|
||||
|
||||
|
||||
def process_auth(
|
||||
credentials: Annotated[Union[str, None], Security(oauth2_scheme)],
|
||||
security_scopes: SecurityScopes,
|
||||
):
|
||||
# This is an incorrect way of using it, this is not checking if the scopes are
|
||||
# provided by the token, only if the endpoint is requesting them, but the test
|
||||
# here is just to check if FastAPI is indeed registering and passing the scopes
|
||||
# correctly when using Security with parameterless dependencies.
|
||||
if "a" not in security_scopes.scopes or "b" not in security_scopes.scopes:
|
||||
raise HTTPException(detail="a or b not in scopes", status_code=401)
|
||||
return {"token": credentials, "scopes": security_scopes.scopes}
|
||||
|
||||
|
||||
@app.get("/get-credentials")
|
||||
def get_credentials(
|
||||
credentials: Annotated[dict, Security(process_auth, scopes=["a", "b"])],
|
||||
):
|
||||
return credentials
|
||||
|
||||
|
||||
@app.get(
|
||||
"/parameterless-with-scopes",
|
||||
dependencies=[Security(process_auth, scopes=["a", "b"])],
|
||||
)
|
||||
def get_parameterless_with_scopes():
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
@app.get(
|
||||
"/parameterless-without-scopes",
|
||||
dependencies=[Security(process_auth)],
|
||||
)
|
||||
def get_parameterless_without_scopes():
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
def test_get_credentials():
|
||||
response = client.get("/get-credentials", headers={"authorization": "Bearer token"})
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {"token": "token", "scopes": ["a", "b"]}
|
||||
|
||||
|
||||
def test_parameterless_with_scopes():
|
||||
response = client.get(
|
||||
"/parameterless-with-scopes", headers={"authorization": "Bearer token"}
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {"status": "ok"}
|
||||
|
||||
|
||||
def test_parameterless_without_scopes():
|
||||
response = client.get(
|
||||
"/parameterless-without-scopes", headers={"authorization": "Bearer token"}
|
||||
)
|
||||
assert response.status_code == 401, response.text
|
||||
assert response.json() == {"detail": "a or b not in scopes"}
|
||||
|
||||
|
||||
def test_call_get_parameterless_without_scopes_for_coverage():
|
||||
assert get_parameterless_without_scopes() == {"status": "ok"}
|
||||
184
tests/test_dependency_yield_scope.py
Normal file
184
tests/test_dependency_yield_scope.py
Normal file
@@ -0,0 +1,184 @@
|
||||
import json
|
||||
from typing import Any, Tuple
|
||||
|
||||
import pytest
|
||||
from fastapi import Depends, FastAPI
|
||||
from fastapi.exceptions import FastAPIError
|
||||
from fastapi.responses import StreamingResponse
|
||||
from fastapi.testclient import TestClient
|
||||
from typing_extensions import Annotated
|
||||
|
||||
|
||||
class Session:
|
||||
def __init__(self) -> None:
|
||||
self.open = True
|
||||
|
||||
|
||||
def dep_session() -> Any:
|
||||
s = Session()
|
||||
yield s
|
||||
s.open = False
|
||||
|
||||
|
||||
SessionFuncDep = Annotated[Session, Depends(dep_session, scope="function")]
|
||||
SessionRequestDep = Annotated[Session, Depends(dep_session, scope="request")]
|
||||
SessionDefaultDep = Annotated[Session, Depends(dep_session)]
|
||||
|
||||
|
||||
class NamedSession:
|
||||
def __init__(self, name: str = "default") -> None:
|
||||
self.name = name
|
||||
self.open = True
|
||||
|
||||
|
||||
def get_named_session(session: SessionRequestDep, session_b: SessionDefaultDep) -> Any:
|
||||
assert session is session_b
|
||||
named_session = NamedSession(name="named")
|
||||
yield named_session, session_b
|
||||
named_session.open = False
|
||||
|
||||
|
||||
NamedSessionsDep = Annotated[Tuple[NamedSession, Session], Depends(get_named_session)]
|
||||
|
||||
|
||||
def get_named_func_session(session: SessionFuncDep) -> Any:
|
||||
named_session = NamedSession(name="named")
|
||||
yield named_session, session
|
||||
named_session.open = False
|
||||
|
||||
|
||||
def get_named_regular_func_session(session: SessionFuncDep) -> Any:
|
||||
named_session = NamedSession(name="named")
|
||||
return named_session, session
|
||||
|
||||
|
||||
BrokenSessionsDep = Annotated[
|
||||
Tuple[NamedSession, Session], Depends(get_named_func_session)
|
||||
]
|
||||
NamedSessionsFuncDep = Annotated[
|
||||
Tuple[NamedSession, Session], Depends(get_named_func_session, scope="function")
|
||||
]
|
||||
|
||||
RegularSessionsDep = Annotated[
|
||||
Tuple[NamedSession, Session], Depends(get_named_regular_func_session)
|
||||
]
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/function-scope")
|
||||
def function_scope(session: SessionFuncDep) -> Any:
|
||||
def iter_data():
|
||||
yield json.dumps({"is_open": session.open})
|
||||
|
||||
return StreamingResponse(iter_data())
|
||||
|
||||
|
||||
@app.get("/request-scope")
|
||||
def request_scope(session: SessionRequestDep) -> Any:
|
||||
def iter_data():
|
||||
yield json.dumps({"is_open": session.open})
|
||||
|
||||
return StreamingResponse(iter_data())
|
||||
|
||||
|
||||
@app.get("/two-scopes")
|
||||
def get_stream_session(
|
||||
function_session: SessionFuncDep, request_session: SessionRequestDep
|
||||
) -> Any:
|
||||
def iter_data():
|
||||
yield json.dumps(
|
||||
{"func_is_open": function_session.open, "req_is_open": request_session.open}
|
||||
)
|
||||
|
||||
return StreamingResponse(iter_data())
|
||||
|
||||
|
||||
@app.get("/sub")
|
||||
def get_sub(sessions: NamedSessionsDep) -> Any:
|
||||
def iter_data():
|
||||
yield json.dumps(
|
||||
{"named_session_open": sessions[0].open, "session_open": sessions[1].open}
|
||||
)
|
||||
|
||||
return StreamingResponse(iter_data())
|
||||
|
||||
|
||||
@app.get("/named-function-scope")
|
||||
def get_named_function_scope(sessions: NamedSessionsFuncDep) -> Any:
|
||||
def iter_data():
|
||||
yield json.dumps(
|
||||
{"named_session_open": sessions[0].open, "session_open": sessions[1].open}
|
||||
)
|
||||
|
||||
return StreamingResponse(iter_data())
|
||||
|
||||
|
||||
@app.get("/regular-function-scope")
|
||||
def get_regular_function_scope(sessions: RegularSessionsDep) -> Any:
|
||||
def iter_data():
|
||||
yield json.dumps(
|
||||
{"named_session_open": sessions[0].open, "session_open": sessions[1].open}
|
||||
)
|
||||
|
||||
return StreamingResponse(iter_data())
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
def test_function_scope() -> None:
|
||||
response = client.get("/function-scope")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["is_open"] is False
|
||||
|
||||
|
||||
def test_request_scope() -> None:
|
||||
response = client.get("/request-scope")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["is_open"] is True
|
||||
|
||||
|
||||
def test_two_scopes() -> None:
|
||||
response = client.get("/two-scopes")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["func_is_open"] is False
|
||||
assert data["req_is_open"] is True
|
||||
|
||||
|
||||
def test_sub() -> None:
|
||||
response = client.get("/sub")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["named_session_open"] is True
|
||||
assert data["session_open"] is True
|
||||
|
||||
|
||||
def test_broken_scope() -> None:
|
||||
with pytest.raises(
|
||||
FastAPIError,
|
||||
match='The dependency "get_named_func_session" has a scope of "request", it cannot depend on dependencies with scope "function"',
|
||||
):
|
||||
|
||||
@app.get("/broken-scope")
|
||||
def get_broken(sessions: BrokenSessionsDep) -> Any: # pragma: no cover
|
||||
pass
|
||||
|
||||
|
||||
def test_named_function_scope() -> None:
|
||||
response = client.get("/named-function-scope")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["named_session_open"] is False
|
||||
assert data["session_open"] is False
|
||||
|
||||
|
||||
def test_regular_function_scope() -> None:
|
||||
response = client.get("/regular-function-scope")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["named_session_open"] is True
|
||||
assert data["session_open"] is False
|
||||
201
tests/test_dependency_yield_scope_websockets.py
Normal file
201
tests/test_dependency_yield_scope_websockets.py
Normal file
@@ -0,0 +1,201 @@
|
||||
from contextvars import ContextVar
|
||||
from typing import Any, Dict, Tuple
|
||||
|
||||
import pytest
|
||||
from fastapi import Depends, FastAPI, WebSocket
|
||||
from fastapi.exceptions import FastAPIError
|
||||
from fastapi.testclient import TestClient
|
||||
from typing_extensions import Annotated
|
||||
|
||||
global_context: ContextVar[Dict[str, Any]] = ContextVar("global_context", default={}) # noqa: B039
|
||||
|
||||
|
||||
class Session:
|
||||
def __init__(self) -> None:
|
||||
self.open = True
|
||||
|
||||
|
||||
async def dep_session() -> Any:
|
||||
s = Session()
|
||||
yield s
|
||||
s.open = False
|
||||
global_state = global_context.get()
|
||||
global_state["session_closed"] = True
|
||||
|
||||
|
||||
SessionFuncDep = Annotated[Session, Depends(dep_session, scope="function")]
|
||||
SessionRequestDep = Annotated[Session, Depends(dep_session, scope="request")]
|
||||
SessionDefaultDep = Annotated[Session, Depends(dep_session)]
|
||||
|
||||
|
||||
class NamedSession:
|
||||
def __init__(self, name: str = "default") -> None:
|
||||
self.name = name
|
||||
self.open = True
|
||||
|
||||
|
||||
def get_named_session(session: SessionRequestDep, session_b: SessionDefaultDep) -> Any:
|
||||
assert session is session_b
|
||||
named_session = NamedSession(name="named")
|
||||
yield named_session, session_b
|
||||
named_session.open = False
|
||||
global_state = global_context.get()
|
||||
global_state["named_session_closed"] = True
|
||||
|
||||
|
||||
NamedSessionsDep = Annotated[Tuple[NamedSession, Session], Depends(get_named_session)]
|
||||
|
||||
|
||||
def get_named_func_session(session: SessionFuncDep) -> Any:
|
||||
named_session = NamedSession(name="named")
|
||||
yield named_session, session
|
||||
named_session.open = False
|
||||
global_state = global_context.get()
|
||||
global_state["named_func_session_closed"] = True
|
||||
|
||||
|
||||
def get_named_regular_func_session(session: SessionFuncDep) -> Any:
|
||||
named_session = NamedSession(name="named")
|
||||
return named_session, session
|
||||
|
||||
|
||||
BrokenSessionsDep = Annotated[
|
||||
Tuple[NamedSession, Session], Depends(get_named_func_session)
|
||||
]
|
||||
NamedSessionsFuncDep = Annotated[
|
||||
Tuple[NamedSession, Session], Depends(get_named_func_session, scope="function")
|
||||
]
|
||||
|
||||
RegularSessionsDep = Annotated[
|
||||
Tuple[NamedSession, Session], Depends(get_named_regular_func_session)
|
||||
]
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.websocket("/function-scope")
|
||||
async def function_scope(websocket: WebSocket, session: SessionFuncDep) -> Any:
|
||||
await websocket.accept()
|
||||
await websocket.send_json({"is_open": session.open})
|
||||
|
||||
|
||||
@app.websocket("/request-scope")
|
||||
async def request_scope(websocket: WebSocket, session: SessionRequestDep) -> Any:
|
||||
await websocket.accept()
|
||||
await websocket.send_json({"is_open": session.open})
|
||||
|
||||
|
||||
@app.websocket("/two-scopes")
|
||||
async def get_stream_session(
|
||||
websocket: WebSocket,
|
||||
function_session: SessionFuncDep,
|
||||
request_session: SessionRequestDep,
|
||||
) -> Any:
|
||||
await websocket.accept()
|
||||
await websocket.send_json(
|
||||
{"func_is_open": function_session.open, "req_is_open": request_session.open}
|
||||
)
|
||||
|
||||
|
||||
@app.websocket("/sub")
|
||||
async def get_sub(websocket: WebSocket, sessions: NamedSessionsDep) -> Any:
|
||||
await websocket.accept()
|
||||
await websocket.send_json(
|
||||
{"named_session_open": sessions[0].open, "session_open": sessions[1].open}
|
||||
)
|
||||
|
||||
|
||||
@app.websocket("/named-function-scope")
|
||||
async def get_named_function_scope(
|
||||
websocket: WebSocket, sessions: NamedSessionsFuncDep
|
||||
) -> Any:
|
||||
await websocket.accept()
|
||||
await websocket.send_json(
|
||||
{"named_session_open": sessions[0].open, "session_open": sessions[1].open}
|
||||
)
|
||||
|
||||
|
||||
@app.websocket("/regular-function-scope")
|
||||
async def get_regular_function_scope(
|
||||
websocket: WebSocket, sessions: RegularSessionsDep
|
||||
) -> Any:
|
||||
await websocket.accept()
|
||||
await websocket.send_json(
|
||||
{"named_session_open": sessions[0].open, "session_open": sessions[1].open}
|
||||
)
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
def test_function_scope() -> None:
|
||||
global_context.set({})
|
||||
global_state = global_context.get()
|
||||
with client.websocket_connect("/function-scope") as websocket:
|
||||
data = websocket.receive_json()
|
||||
assert data["is_open"] is True
|
||||
assert global_state["session_closed"] is True
|
||||
|
||||
|
||||
def test_request_scope() -> None:
|
||||
global_context.set({})
|
||||
global_state = global_context.get()
|
||||
with client.websocket_connect("/request-scope") as websocket:
|
||||
data = websocket.receive_json()
|
||||
assert data["is_open"] is True
|
||||
assert global_state["session_closed"] is True
|
||||
|
||||
|
||||
def test_two_scopes() -> None:
|
||||
global_context.set({})
|
||||
global_state = global_context.get()
|
||||
with client.websocket_connect("/two-scopes") as websocket:
|
||||
data = websocket.receive_json()
|
||||
assert data["func_is_open"] is True
|
||||
assert data["req_is_open"] is True
|
||||
assert global_state["session_closed"] is True
|
||||
|
||||
|
||||
def test_sub() -> None:
|
||||
global_context.set({})
|
||||
global_state = global_context.get()
|
||||
with client.websocket_connect("/sub") as websocket:
|
||||
data = websocket.receive_json()
|
||||
assert data["named_session_open"] is True
|
||||
assert data["session_open"] is True
|
||||
assert global_state["session_closed"] is True
|
||||
assert global_state["named_session_closed"] is True
|
||||
|
||||
|
||||
def test_broken_scope() -> None:
|
||||
with pytest.raises(
|
||||
FastAPIError,
|
||||
match='The dependency "get_named_func_session" has a scope of "request", it cannot depend on dependencies with scope "function"',
|
||||
):
|
||||
|
||||
@app.websocket("/broken-scope")
|
||||
async def get_broken(
|
||||
websocket: WebSocket, sessions: BrokenSessionsDep
|
||||
) -> Any: # pragma: no cover
|
||||
pass
|
||||
|
||||
|
||||
def test_named_function_scope() -> None:
|
||||
global_context.set({})
|
||||
global_state = global_context.get()
|
||||
with client.websocket_connect("/named-function-scope") as websocket:
|
||||
data = websocket.receive_json()
|
||||
assert data["named_session_open"] is True
|
||||
assert data["session_open"] is True
|
||||
assert global_state["session_closed"] is True
|
||||
assert global_state["named_func_session_closed"] is True
|
||||
|
||||
|
||||
def test_regular_function_scope() -> None:
|
||||
global_context.set({})
|
||||
global_state = global_context.get()
|
||||
with client.websocket_connect("/regular-function-scope") as websocket:
|
||||
data = websocket.receive_json()
|
||||
assert data["named_session_open"] is True
|
||||
assert data["session_open"] is True
|
||||
assert global_state["session_closed"] is True
|
||||
@@ -1,7 +1,7 @@
|
||||
from typing import Any, List
|
||||
|
||||
from dirty_equals import IsOneOf
|
||||
from fastapi.params import Body, Cookie, Depends, Header, Param, Path, Query
|
||||
from fastapi.params import Body, Cookie, Header, Param, Path, Query
|
||||
|
||||
test_data: List[Any] = ["teststr", None, ..., 1, []]
|
||||
|
||||
@@ -141,12 +141,3 @@ def test_body_repr_number():
|
||||
|
||||
def test_body_repr_list():
|
||||
assert repr(Body([])) == "Body([])"
|
||||
|
||||
|
||||
def test_depends_repr():
|
||||
assert repr(Depends()) == "Depends(NoneType)"
|
||||
assert repr(Depends(get_user)) == "Depends(get_user)"
|
||||
assert repr(Depends(use_cache=False)) == "Depends(NoneType, use_cache=False)"
|
||||
assert (
|
||||
repr(Depends(get_user, use_cache=False)) == "Depends(get_user, use_cache=False)"
|
||||
)
|
||||
|
||||
60
tests/test_top_level_security_scheme_in_openapi.py
Normal file
60
tests/test_top_level_security_scheme_in_openapi.py
Normal file
@@ -0,0 +1,60 @@
|
||||
# Test security scheme at the top level, including OpenAPI
|
||||
# Ref: https://github.com/fastapi/fastapi/discussions/14263
|
||||
# Ref: https://github.com/fastapi/fastapi/issues/14271
|
||||
from fastapi import Depends, FastAPI
|
||||
from fastapi.security import HTTPBearer
|
||||
from fastapi.testclient import TestClient
|
||||
from inline_snapshot import snapshot
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
bearer_scheme = HTTPBearer()
|
||||
|
||||
|
||||
@app.get("/", dependencies=[Depends(bearer_scheme)])
|
||||
async def get_root():
|
||||
return {"message": "Hello, World!"}
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
def test_get_root():
|
||||
response = client.get("/", headers={"Authorization": "Bearer token"})
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == {"message": "Hello, World!"}
|
||||
|
||||
|
||||
def test_get_root_no_token():
|
||||
response = client.get("/")
|
||||
assert response.status_code == 403, response.text
|
||||
assert response.json() == {"detail": "Not authenticated"}
|
||||
|
||||
|
||||
def test_openapi_schema():
|
||||
response = client.get("/openapi.json")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == snapshot(
|
||||
{
|
||||
"openapi": "3.1.0",
|
||||
"info": {"title": "FastAPI", "version": "0.1.0"},
|
||||
"paths": {
|
||||
"/": {
|
||||
"get": {
|
||||
"summary": "Get Root",
|
||||
"operationId": "get_root__get",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {"application/json": {"schema": {}}},
|
||||
}
|
||||
},
|
||||
"security": [{"HTTPBearer": []}],
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"securitySchemes": {"HTTPBearer": {"type": "http", "scheme": "bearer"}}
|
||||
},
|
||||
}
|
||||
)
|
||||
27
tests/test_tutorial/test_dependencies/test_tutorial008e.py
Normal file
27
tests/test_tutorial/test_dependencies/test_tutorial008e.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import importlib
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from ...utils import needs_py39
|
||||
|
||||
|
||||
@pytest.fixture(
|
||||
name="client",
|
||||
params=[
|
||||
"tutorial008e",
|
||||
"tutorial008e_an",
|
||||
pytest.param("tutorial008e_an_py39", marks=needs_py39),
|
||||
],
|
||||
)
|
||||
def get_client(request: pytest.FixtureRequest):
|
||||
mod = importlib.import_module(f"docs_src.dependencies.{request.param}")
|
||||
|
||||
client = TestClient(mod.app)
|
||||
return client
|
||||
|
||||
|
||||
def test_get_users_me(client: TestClient):
|
||||
response = client.get("/users/me")
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json() == "Rick"
|
||||
Reference in New Issue
Block a user