Coverage for src/lexigram/graphql/exceptions.py: 100%

61 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-25 04:37 +0800

1"""GraphQL exceptions - complete exception hierarchy.""" 

2 

3from __future__ import annotations 

4 

5from typing import Any 

6 

7from lexigram.contracts.exceptions import ( 

8 AuthenticationError as _ContractsAuthenticationError, 

9) 

10from lexigram.contracts.exceptions import ( 

11 AuthorizationError as _ContractsAuthorizationError, 

12) 

13from lexigram.contracts.exceptions import LexigramError 

14from lexigram.graphql.types import GraphQLErrorCode 

15 

16 

17class GraphQLError(LexigramError): 

18 """Base exception for all GraphQL errors.""" 

19 

20 _code: str = "LEX_ERR_GQL_001" 

21 code: GraphQLErrorCode = GraphQLErrorCode.INTERNAL_SERVER_ERROR 

22 safe: bool = False # Whether error message can be shown to users 

23 

24 def __init__( 

25 self, message: str, *, code: GraphQLErrorCode | None = None, **kwargs: Any 

26 ) -> None: 

27 # Use class attribute code if not explicitly provided 

28 effective_code = code if code is not None else self.__class__.code 

29 super().__init__(message) 

30 self.code = effective_code 

31 self.extensions = kwargs 

32 

33 

34class ExecutionError(GraphQLError): 

35 """Raised when execution fails.""" 

36 

37 _code: str = "LEX_ERR_GQL_002" 

38 

39 

40class GraphQLTimeoutError(ExecutionError): 

41 """Raised when execution times out.""" 

42 

43 _code: str = "LEX_ERR_GQL_003" 

44 

45 

46class QueryTooDeepError(GraphQLError): 

47 """Raised when a GraphQL query exceeds the maximum depth.""" 

48 

49 _code: str = "LEX_ERR_GQL_004" 

50 code = GraphQLErrorCode.QUERY_TOO_DEEP 

51 safe = True 

52 

53 

54# --- Validation --- 

55class InputGraphQLError(GraphQLError): 

56 """Raised for invalid user input.""" 

57 

58 _code: str = "LEX_ERR_GQL_005" 

59 code = GraphQLErrorCode.BAD_USER_INPUT 

60 safe = True 

61 

62 

63class ParseError(GraphQLError): 

64 """Raised when query parsing fails.""" 

65 

66 _code: str = "LEX_ERR_GQL_006" 

67 code = GraphQLErrorCode.GRAPHQL_PARSE_FAILED 

68 

69 

70class QueryTooComplexError(GraphQLError): 

71 """Raised when query exceeds complexity limit.""" 

72 

73 _code: str = "LEX_ERR_GQL_007" 

74 code = GraphQLErrorCode.QUERY_TOO_COMPLEX 

75 safe = True 

76 

77 

78class ResolverError(GraphQLError): 

79 """Raised when a resolver fails.""" 

80 

81 _code: str = "LEX_ERR_GQL_008" 

82 

83 

84# --- Auth --- 

85class AuthenticationError(GraphQLError, _ContractsAuthenticationError): 

86 """Raised when authentication is required but missing. 

87 

88 Also satisfies ``lexigram.contracts.exceptions.AuthenticationError`` so 

89 middleware that catches the contracts type will catch this as well. 

90 """ 

91 

92 _code: str = "LEX_ERR_GQL_009" 

93 code = GraphQLErrorCode.UNAUTHENTICATED 

94 safe = True 

95 

96 

97class AuthorizationError(GraphQLError, _ContractsAuthorizationError): 

98 """Raised when user is authenticated but lacks permissions. 

99 

100 Also satisfies ``lexigram.contracts.exceptions.AuthorizationError`` so 

101 middleware that catches the contracts type will catch this as well. 

102 """ 

103 

104 _code: str = "LEX_ERR_GQL_010" 

105 code = GraphQLErrorCode.UNAUTHORIZED 

106 safe = True 

107 

108 

109class ForbiddenError(GraphQLError): 

110 """Raised when access is forbidden.""" 

111 

112 _code: str = "LEX_ERR_GQL_011" 

113 code = GraphQLErrorCode.FORBIDDEN 

114 safe = True 

115 

116 

117class NotFoundError(GraphQLError): 

118 """Raised when a requested resource is not found.""" 

119 

120 _code: str = "LEX_ERR_GQL_012" 

121 code = GraphQLErrorCode.NOT_FOUND 

122 safe = True 

123 

124 

125# --- Security --- 

126class RateLimitError(GraphQLError): 

127 """Raised when rate limit is exceeded.""" 

128 

129 _code: str = "LEX_ERR_GQL_013" 

130 code = GraphQLErrorCode.RATE_LIMITED 

131 safe = True 

132 

133 

134# --- Subscriptions --- 

135class SubscriptionError(GraphQLError): 

136 """Raised for subscription-related errors.""" 

137 

138 _code: str = "LEX_ERR_GQL_014" 

139 

140 

141# --- Network --- 

142class GraphQLConnectionError(GraphQLError): 

143 """Raised when a network connection error occurs during GraphQL execution.""" 

144 

145 _code: str = "LEX_ERR_GQL_015" 

146 

147 

148__all__ = [ 

149 # Auth 

150 "AuthenticationError", 

151 "AuthorizationError", 

152 # Execution 

153 "ExecutionError", 

154 "ForbiddenError", 

155 # Network 

156 "GraphQLConnectionError", 

157 # Base 

158 "GraphQLError", 

159 "GraphQLTimeoutError", 

160 # Validation 

161 "InputGraphQLError", 

162 "NotFoundError", 

163 "ParseError", 

164 "QueryTooComplexError", 

165 "QueryTooDeepError", 

166 # Security 

167 "RateLimitError", 

168 "ResolverError", 

169 # Subscriptions 

170 "SubscriptionError", 

171]