/ exceptions.py
exceptions.py
 1  """Custom exception hierarchy for the job-search application."""
 2  
 3  __all__ = [
 4      "JobSearchError",
 5      "ConfigurationError",
 6      "APIError",
 7      "ParseError",
 8      "DataError",
 9      "UsageError",
10  ]
11  
12  
13  class JobSearchError(Exception):
14      """Base exception for all application errors."""
15  
16  
17  class ConfigurationError(JobSearchError):
18      """Raised when a required configuration value is missing or invalid.
19  
20      Args:
21          var_name: The name of the missing or invalid environment variable.
22      """
23  
24      def __init__(self, var_name: str) -> None:
25          self.var_name = var_name
26          super().__init__(f"Missing or invalid configuration: {var_name!r}")
27  
28  
29  class APIError(JobSearchError):
30      """Raised when an external API call fails with a non-retriable error.
31  
32      Args:
33          service: Name of the external service (e.g. 'brightdata', 'anthropic').
34          status_code: HTTP status code returned by the service.
35          message: Human-readable error detail.
36      """
37  
38      def __init__(self, service: str, status_code: int, message: str) -> None:
39          self.service = service
40          self.status_code = status_code
41          super().__init__(f"[{service}] HTTP {status_code}: {message}")
42  
43  
44  class ParseError(JobSearchError):
45      """Raised when response data cannot be parsed into the expected schema.
46  
47      Args:
48          source: Where the data came from (e.g. 'brightdata snapshot').
49          detail: Description of what failed.
50          raw: The raw response that failed validation (for diagnostics).
51      """
52  
53      def __init__(self, source: str, detail: str, *, raw: str | None = None) -> None:
54          self.source = source
55          self.raw = raw
56          super().__init__(f"Failed to parse response from {source!r}: {detail}")
57  
58  
59  class DataError(JobSearchError):
60      """Raised when input data is invalid or incomplete and cannot be processed.
61  
62      Args:
63          detail: Human-readable description of the data problem.
64      """
65  
66      def __init__(self, detail: str) -> None:
67          super().__init__(f"Input data error: {detail}")
68  
69  
70  class UsageError(JobSearchError):
71      """Raised when the caller supplies an invalid combination of CLI arguments.
72  
73      Args:
74          detail: Human-readable description of the invalid usage.
75      """
76  
77      def __init__(self, detail: str) -> None:
78          super().__init__(f"Invalid usage: {detail}")