OpenCite raises a small hierarchy of exceptions, all rooted at
OpenCiteError. Catch the base class to handle any OpenCite-specific failure,
or a specific subclass for finer control.
fromopencite.exceptionsimportOpenCiteError,APIKeyError,RateLimitErrortry:...exceptAPIKeyError:...# missing or invalid API keyexceptRateLimitError:...# upstream rate limit hitexceptOpenCiteError:...# any other OpenCite error
classOpenCiteError(Exception):"""Base exception for all opencite errors."""def__init__(self,message:str,details:str|None=None):super().__init__(message)self.message=messageself.details=detailsdef__str__(self)->str:ifself.details:returnf"{self.message}\nDetails: {self.details}"returnself.message
classAPIError(OpenCiteError):"""Base for all API communication errors."""def__init__(self,message:str,status_code:int|None=None,cause:Exception|None=None,details:str|None=None,):super().__init__(message,details)self.status_code=status_codeself.cause=cause@classmethoddeffrom_http_error(cls,error:Exception,status_code:int)->APIError:ifstatus_codein(401,403):returnAPIKeyError(str(error))ifstatus_code==429:returnRateLimitError(cause=error)returncls(f"HTTP {status_code}: {error}",status_code=status_code,cause=error)
classAPIKeyError(APIError):"""Invalid or missing API key."""def__init__(self,message:str="Invalid or missing API key"):super().__init__(message,details="Check that the required API key environment variable is set.",)
classRateLimitError(APIError):"""Rate limit exceeded."""def__init__(self,retry_after:int|None=None,cause:Exception|None=None,):message="Rate limit exceeded"details="Too many requests. The client will retry automatically."ifretry_after:details+=f" Retry after {retry_after}s."super().__init__(message,details=details,cause=cause)self.retry_after=retry_after