Coverage for tests/test_inherited_custom_class.py: 100%

69 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2025-05-05 00:03 +0000

1import uuid 1mnopqr

2 

3import pytest 1mnopqr

4from fastapi import FastAPI 1mnopqr

5from fastapi.testclient import TestClient 1mnopqr

6from pydantic import BaseModel 1mnopqr

7 

8from .utils import needs_pydanticv1, needs_pydanticv2 1mnopqr

9 

10 

11class MyUuid: 1mnopqr

12 def __init__(self, uuid_string: str): 1mnopqr

13 self.uuid = uuid_string 1gahbicjdkelf

14 

15 def __str__(self): 1mnopqr

16 return self.uuid 1gahbicjdkelf

17 

18 @property # type: ignore 1mnopqr

19 def __class__(self): 1mnopqr

20 return uuid.UUID 1gahbicjdkelf

21 

22 @property 1mnopqr

23 def __dict__(self): 1mnopqr

24 """Spoof a missing __dict__ by raising TypeError, this is how 

25 asyncpg.pgroto.pgproto.UUID behaves""" 

26 raise TypeError("vars() argument must have __dict__ attribute") 1gahbicjdkelf

27 

28 

29@needs_pydanticv2 1mnopqr

30def test_pydanticv2(): 1mnopqr

31 from pydantic import field_serializer 1abcdef

32 

33 app = FastAPI() 1abcdef

34 

35 @app.get("/fast_uuid") 1abcdef

36 def return_fast_uuid(): 1abcdef

37 asyncpg_uuid = MyUuid("a10ff360-3b1e-4984-a26f-d3ab460bdb51") 1abcdef

38 assert isinstance(asyncpg_uuid, uuid.UUID) 1abcdef

39 assert type(asyncpg_uuid) is not uuid.UUID 1abcdef

40 with pytest.raises(TypeError): 1abcdef

41 vars(asyncpg_uuid) 1abcdef

42 return {"fast_uuid": asyncpg_uuid} 1abcdef

43 

44 class SomeCustomClass(BaseModel): 1abcdef

45 model_config = {"arbitrary_types_allowed": True} 1abcdef

46 

47 a_uuid: MyUuid 1abcdef

48 

49 @field_serializer("a_uuid") 1abcdef

50 def serialize_a_uuid(self, v): 1abcdef

51 return str(v) 1abcdef

52 

53 @app.get("/get_custom_class") 1abcdef

54 def return_some_user(): 1abcdef

55 # Test that the fix also works for custom pydantic classes 

56 return SomeCustomClass(a_uuid=MyUuid("b8799909-f914-42de-91bc-95c819218d01")) 1abcdef

57 

58 client = TestClient(app) 1abcdef

59 

60 with client: 1abcdef

61 response_simple = client.get("/fast_uuid") 1abcdef

62 response_pydantic = client.get("/get_custom_class") 1abcdef

63 

64 assert response_simple.json() == { 1abcdef

65 "fast_uuid": "a10ff360-3b1e-4984-a26f-d3ab460bdb51" 

66 } 

67 

68 assert response_pydantic.json() == { 1abcdef

69 "a_uuid": "b8799909-f914-42de-91bc-95c819218d01" 

70 } 

71 

72 

73# TODO: remove when deprecating Pydantic v1 

74@needs_pydanticv1 1mnopqr

75def test_pydanticv1(): 1mnopqr

76 app = FastAPI() 1ghijkl

77 

78 @app.get("/fast_uuid") 1ghijkl

79 def return_fast_uuid(): 1ghijkl

80 asyncpg_uuid = MyUuid("a10ff360-3b1e-4984-a26f-d3ab460bdb51") 1ghijkl

81 assert isinstance(asyncpg_uuid, uuid.UUID) 1ghijkl

82 assert type(asyncpg_uuid) is not uuid.UUID 1ghijkl

83 with pytest.raises(TypeError): 1ghijkl

84 vars(asyncpg_uuid) 1ghijkl

85 return {"fast_uuid": asyncpg_uuid} 1ghijkl

86 

87 class SomeCustomClass(BaseModel): 1ghijkl

88 class Config: 1ghijkl

89 arbitrary_types_allowed = True 1ghijkl

90 json_encoders = {uuid.UUID: str} 1ghijkl

91 

92 a_uuid: MyUuid 1ghijkl

93 

94 @app.get("/get_custom_class") 1ghijkl

95 def return_some_user(): 1ghijkl

96 # Test that the fix also works for custom pydantic classes 

97 return SomeCustomClass(a_uuid=MyUuid("b8799909-f914-42de-91bc-95c819218d01")) 1ghijkl

98 

99 client = TestClient(app) 1ghijkl

100 

101 with client: 1ghijkl

102 response_simple = client.get("/fast_uuid") 1ghijkl

103 response_pydantic = client.get("/get_custom_class") 1ghijkl

104 

105 assert response_simple.json() == { 1ghijkl

106 "fast_uuid": "a10ff360-3b1e-4984-a26f-d3ab460bdb51" 

107 } 

108 

109 assert response_pydantic.json() == { 1ghijkl

110 "a_uuid": "b8799909-f914-42de-91bc-95c819218d01" 

111 }