Coverage for tests / test_security_scopes_sub_dependency.py: 100%

38 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-02-12 18:15 +0000

1# Ref: https://github.com/fastapi/fastapi/discussions/6024#discussioncomment-8541913 

2 

3 

4from typing import Annotated 1abgc

5 

6import pytest 1abgc

7from fastapi import Depends, FastAPI, Security 1abgc

8from fastapi.security import SecurityScopes 1abgc

9from fastapi.testclient import TestClient 1abgc

10 

11 

12@pytest.fixture(name="call_counts") 1abgc

13def call_counts_fixture(): 1abgc

14 return { 1abc

15 "get_db_session": 0, 

16 "get_current_user": 0, 

17 "get_user_me": 0, 

18 "get_user_items": 0, 

19 } 

20 

21 

22@pytest.fixture(name="app") 1abgc

23def app_fixture(call_counts: dict[str, int]): 1abgc

24 def get_db_session(): 1abc

25 call_counts["get_db_session"] += 1 1def

26 return f"db_session_{call_counts['get_db_session']}" 1def

27 

28 def get_current_user( 1abc

29 security_scopes: SecurityScopes, 

30 db_session: Annotated[str, Depends(get_db_session)], 

31 ): 

32 call_counts["get_current_user"] += 1 1def

33 return { 1def

34 "user": f"user_{call_counts['get_current_user']}", 

35 "scopes": security_scopes.scopes, 

36 "db_session": db_session, 

37 } 

38 

39 def get_user_me( 1abc

40 current_user: Annotated[dict, Security(get_current_user, scopes=["me"])], 

41 ): 

42 call_counts["get_user_me"] += 1 1def

43 return { 1def

44 "user_me": f"user_me_{call_counts['get_user_me']}", 

45 "current_user": current_user, 

46 } 

47 

48 def get_user_items( 1abc

49 user_me: Annotated[dict, Depends(get_user_me)], 

50 ): 

51 call_counts["get_user_items"] += 1 1def

52 return { 1def

53 "user_items": f"user_items_{call_counts['get_user_items']}", 

54 "user_me": user_me, 

55 } 

56 

57 app = FastAPI() 1abc

58 

59 @app.get("/") 1abc

60 def path_operation( 1abc

61 user_me: Annotated[dict, Depends(get_user_me)], 

62 user_items: Annotated[dict, Security(get_user_items, scopes=["items"])], 

63 ): 

64 return { 1def

65 "user_me": user_me, 

66 "user_items": user_items, 

67 } 

68 

69 return app 1abc

70 

71 

72@pytest.fixture(name="client") 1abgc

73def client_fixture(app: FastAPI): 1abgc

74 return TestClient(app) 1abc

75 

76 

77def test_security_scopes_sub_dependency_caching( 1abgc

78 client: TestClient, call_counts: dict[str, int] 

79): 

80 response = client.get("/") 1def

81 

82 assert response.status_code == 200 1def

83 assert call_counts["get_db_session"] == 1 1def

84 assert call_counts["get_current_user"] == 2 1def

85 assert call_counts["get_user_me"] == 2 1def

86 assert call_counts["get_user_items"] == 1 1def

87 assert response.json() == { 1def

88 "user_me": { 

89 "user_me": "user_me_1", 

90 "current_user": { 

91 "user": "user_1", 

92 "scopes": ["me"], 

93 "db_session": "db_session_1", 

94 }, 

95 }, 

96 "user_items": { 

97 "user_items": "user_items_1", 

98 "user_me": { 

99 "user_me": "user_me_2", 

100 "current_user": { 

101 "user": "user_2", 

102 "scopes": ["items", "me"], 

103 "db_session": "db_session_1", 

104 }, 

105 }, 

106 }, 

107 }