Coverage for youversion/models/friends.py: 100%

45 statements  

« prev     ^ index     » next       coverage.py v7.14.3, created at 2026-06-26 11:31 +0100

1"""Friends and social features data models.""" 

2 

3from datetime import datetime 

4from typing import Any, Protocol 

5 

6try: 

7 from typing import TypeAlias 

8except ImportError: 

9 # Python < 3.10 compatibility 

10 from typing import TypeAlias 

11 

12from .common import UserBase 

13 

14 

15class ContactProtocol(Protocol): 

16 """Protocol for contact information.""" 

17 

18 email: str 

19 name: str | None 

20 phone: str | None 

21 

22 def __getattr__(self, name: str) -> Any: 

23 """Allow access to dynamically added fields.""" 

24 class_name = self.__class__.__name__ 

25 raise AttributeError(f"'{class_name}' has no attribute '{name}'") 

26 

27 

28# Type alias for convenience 

29Contact: TypeAlias = ContactProtocol 

30 

31 

32class ContactsProtocol(Protocol): 

33 """Protocol for contacts list.""" 

34 

35 contacts: list[Contact] 

36 

37 def __getattr__(self, name: str) -> Any: 

38 """Allow access to dynamically added fields.""" 

39 class_name = self.__class__.__name__ 

40 raise AttributeError(f"'{class_name}' has no attribute '{name}'") 

41 

42 

43# Type alias for convenience 

44Contacts: TypeAlias = ContactsProtocol 

45 

46 

47class FriendProtocol(Protocol): 

48 """Protocol for friend information.""" 

49 

50 user: UserBase 

51 friendship_id: int | None 

52 created_dt: datetime | None 

53 

54 def __getattr__(self, name: str) -> Any: 

55 """Allow access to dynamically added fields.""" 

56 class_name = self.__class__.__name__ 

57 raise AttributeError(f"'{class_name}' has no attribute '{name}'") 

58 

59 

60# Type alias for convenience 

61Friend: TypeAlias = FriendProtocol 

62 

63 

64class FriendsProtocol(Protocol): 

65 """Protocol for friends list.""" 

66 

67 friends: list[Friend] 

68 total: int 

69 

70 def __getattr__(self, name: str) -> Any: 

71 """Allow access to dynamically added fields.""" 

72 class_name = self.__class__.__name__ 

73 raise AttributeError(f"'{class_name}' has no attribute '{name}'") 

74 

75 

76# Type alias for convenience 

77Friends: TypeAlias = FriendsProtocol 

78 

79 

80class FriendOfferProtocol(Protocol): 

81 """Protocol for friend offer/request information.""" 

82 

83 id: int 

84 from_user: UserBase 

85 to_user: UserBase 

86 status: str 

87 created_dt: datetime | None 

88 

89 def __getattr__(self, name: str) -> Any: 

90 """Allow access to dynamically added fields.""" 

91 class_name = self.__class__.__name__ 

92 raise AttributeError(f"'{class_name}' has no attribute '{name}'") 

93 

94 

95# Type alias for convenience 

96FriendOffer: TypeAlias = FriendOfferProtocol 

97 

98 

99class OffersProtocol(Protocol): 

100 """Protocol for friend offers list.""" 

101 

102 offers: list[FriendOffer] 

103 total: int 

104 

105 def __getattr__(self, name: str) -> Any: 

106 """Allow access to dynamically added fields.""" 

107 class_name = self.__class__.__name__ 

108 raise AttributeError(f"'{class_name}' has no attribute '{name}'") 

109 

110 

111# Type alias for convenience 

112Offers: TypeAlias = OffersProtocol 

113 

114 

115class FriendableProtocol(Protocol): 

116 """Protocol for friendable user (suggestion).""" 

117 

118 user: UserBase 

119 reason: str | None 

120 mutual_friends: int | None 

121 

122 def __getattr__(self, name: str) -> Any: 

123 """Allow access to dynamically added fields.""" 

124 class_name = self.__class__.__name__ 

125 raise AttributeError(f"'{class_name}' has no attribute '{name}'") 

126 

127 

128# Type alias for convenience 

129Friendable: TypeAlias = FriendableProtocol 

130 

131 

132class FriendablesProtocol(Protocol): 

133 """Protocol for friendable users list.""" 

134 

135 users: list[Friendable] 

136 total: int 

137 

138 def __getattr__(self, name: str) -> Any: 

139 """Allow access to dynamically added fields.""" 

140 class_name = self.__class__.__name__ 

141 raise AttributeError(f"'{class_name}' has no attribute '{name}'") 

142 

143 

144# Type alias for convenience 

145Friendables: TypeAlias = FriendablesProtocol