# -*- coding: utf-8 -*-
"""
:Module: freshpy.errors.exceptions
:Synopsis: Collection of exception classes relating to the freshpy library
:Created By: Jeff Shurtliff
:Last Modified: Jeff Shurtliff
:Modified Date: 02 Jan 2026
"""
# Define constants
FOLLOWING_SEGMENT = ' with the following'
#################
# Base Exception
#################
# Define base exception class
[docs]
class FreshPyError(Exception):
"""This is the base class for FreshPy exceptions.
.. version-added:: 1.0.0
"""
pass
############################
# Authentication Exceptions
############################
[docs]
class MissingAuthDataError(FreshPyError):
"""This exception is used when authentication data is not supplied and therefore a connection cannot occur.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "The authentication data was not provided and a connection cannot be established."
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
super().__init__(*args)
#####################
# General Exceptions
#####################
[docs]
class CurrentlyUnsupportedError(FreshPyError):
"""This exception is used when a feature or functionality being used is currently unsupported.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "This feature is currently unsupported at this time."
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
else:
custom_msg = f"The '{args[0]}' {default_msg.split('This ')[1]}"
args = (custom_msg,)
super().__init__(*args)
[docs]
class DataMismatchError(FreshPyError):
"""This exception is used when there is a mismatch between two data sources.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "A data mismatch was found with the data sources."
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
elif 'data' in kwargs:
multi_types = [list, tuple, set]
if isinstance(kwargs['data'], str):
custom_msg = f"{default_msg.split('data')[0]}'{kwargs['val']}'{default_msg.split('with the')[1]}"
custom_msg = custom_msg.replace('sources', 'source')
args = (custom_msg,)
elif type(kwargs['data']) in multi_types and len(kwargs['data']) == 2:
custom_section = f"'{kwargs['data'][0]}' and '{kwargs['data'][1]}'"
custom_msg = f"{default_msg.split('data sources')[0]}{custom_section}{default_msg.split('with the')[1]}"
args = (custom_msg,)
super().__init__(*args)
[docs]
class InvalidDataTypeError(FreshPyError):
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "The data type for the parameter is invalid."
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
if 'param' in kwargs:
new_str_segment = f"'{kwargs['param']}' parameter"
custom_msg = f"{default_msg.replace('parameter', new_str_segment)}"
args = (custom_msg,)
super().__init__(*args)
[docs]
class InvalidFieldError(FreshPyError):
"""This exception is used when an invalid field is provided.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "The field that was provided is invalid."
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
elif 'val' in kwargs:
custom_msg = f"{default_msg.split('field ')[0]}'{kwargs['val']}'{default_msg.split('The')[1]}"
args = (custom_msg,)
super().__init__(*args)
[docs]
class InvalidFilterError(FreshPyError):
"""This exception is used when an invalid filter for an API call is provided.
.. version-added:: 2.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "The supplied filter is invalid."
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
super().__init__(*args)
[docs]
class InvalidURLError(FreshPyError):
"""This exception is used when a provided URL is invalid.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "The provided URL is invalid"
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
elif 'url' in kwargs:
custom_msg = f"{default_msg.split('is')[0]}'{kwargs['url']}'{default_msg.split('URL')[1]}"
args = (custom_msg,)
super().__init__(*args)
[docs]
class MissingRequiredDataError(FreshPyError):
"""This exception is used when a function or method is missing one or more required arguments.
.. version-changed:: 3.0.0
It is now possible to specify the missing argument for the init message.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "Missing one or more required parameters"
init_msg = "The object failed to initialize as it is missing one or more required arguments."
param_msg = "The required parameter 'PARAMETER_NAME' is not defined"
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
elif 'init' in args or 'initialize' in args:
if 'object' in kwargs:
custom_msg = f"{init_msg.split('object')[0]}'{kwargs['object']}'{init_msg.split('The')[1]}"
args = (custom_msg,)
elif 'argument' in kwargs:
msg_segment = 'one or more required arguments'
custom_msg = f"{init_msg.split(msg_segment)[0]}the \'{kwargs['argument']}\' required argument."
args = (custom_msg,)
else:
args = (init_msg,)
elif 'param' in kwargs:
args = (param_msg.replace('PARAMETER_NAME', kwargs['param']),)
else:
args = (default_msg,)
super().__init__(*args)
#########################
# Generic API Exceptions
#########################
[docs]
class APIConnectionError(FreshPyError):
"""This exception is used when the API query could not be completed due to connection aborts and/or timeouts.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "The API query could not be completed due to connection aborts and/or timeouts."
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
super().__init__(*args)
[docs]
class APIRequestError(FreshPyError):
"""This exception is used for generic API request errors when there isn't a more specific exception.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "The API request did not return a successful response."
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
super().__init__(*args)
[docs]
class DELETERequestError(FreshPyError):
"""This exception is used for generic DELETE request errors when there isn't a more specific exception.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "The DELETE request did not return a successful response."
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
super().__init__(*args)
[docs]
class GETRequestError(FreshPyError):
"""This exception is used for generic GET request errors when there is not a more specific exception.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "The GET request did not return a successful response."
custom_msg = "The GET request failed with the following message:"
if 'status_code' in kwargs or 'message' in kwargs:
if 'status_code' in kwargs:
status_code_msg = f"returned the {kwargs['status_code']} status code"
custom_msg = custom_msg.replace('failed', status_code_msg)
if 'message' in kwargs:
custom_msg = f"{custom_msg} {kwargs['message']}"
else:
custom_msg = custom_msg.split(FOLLOWING_SEGMENT)[0] + "."
args = (custom_msg,)
elif not (args or kwargs) or args[0] is None:
args = (default_msg,)
super().__init__(*args)
[docs]
class InvalidPayloadValueError(FreshPyError):
"""This exception is used when an invalid value is provided for a payload field.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "An invalid payload value was provided."
custom_msg = "The invalid payload value 'X' was provided for the 'Y' field."
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
elif 'value' in kwargs:
if 'field' in kwargs:
custom_msg = custom_msg.replace('X', kwargs['value']).replace('Y', kwargs['field'])
else:
custom_msg = f"{custom_msg.replace('X', kwargs['value']).split(' for the')[0]}."
args = (custom_msg,)
super().__init__(*args)
[docs]
class InvalidRequestTypeError(FreshPyError):
"""This exception is used when an invalid API request type is provided.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "The supplied request type for the API is not recognized. (Examples of valid " + \
"request types include 'POST' and 'PUT')"
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
super().__init__(*args)
[docs]
class LookupMismatchError(FreshPyError):
"""This exception is used when a lookup value does not match the supplied lookup type.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "The supplied lookup type for the API does not match the value that was provided."
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
super().__init__(*args)
[docs]
class NotFoundResponseError(FreshPyError):
"""This exception is used when an API query returns a 404 response and there isn't a more specific class.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "The API query returned a 404 response."
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
super().__init__(*args)
[docs]
class PATCHRequestError(FreshPyError):
"""This exception is used for generic PATCH request errors when there isn't a more specific exception.
.. version-added:: 3.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "The PATCH request did not return a successful response."
custom_msg = "The PATCH request failed with the following message:"
if 'status_code' in kwargs or 'message' in kwargs:
if 'status_code' in kwargs:
status_code_msg = f"returned the {kwargs['status_code']} status code"
custom_msg = custom_msg.replace('failed', status_code_msg)
if 'message' in kwargs:
custom_msg = f"{custom_msg} {kwargs['message']}"
else:
custom_msg = custom_msg.split(FOLLOWING_SEGMENT)[0] + "."
args = (custom_msg,)
elif not (args or kwargs) or args[0] is None:
args = (default_msg,)
super().__init__(*args)
[docs]
class POSTRequestError(FreshPyError):
"""This exception is used for generic POST request errors when there isn't a more specific exception.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "The POST request did not return a successful response."
custom_msg = "The POST request failed with the following message:"
if 'status_code' in kwargs or 'message' in kwargs:
if 'status_code' in kwargs:
status_code_msg = f"returned the {kwargs['status_code']} status code"
custom_msg = custom_msg.replace('failed', status_code_msg)
if 'message' in kwargs:
custom_msg = f"{custom_msg} {kwargs['message']}"
else:
custom_msg = custom_msg.split(FOLLOWING_SEGMENT)[0] + "."
args = (custom_msg,)
elif not (args or kwargs) or args[0] is None:
args = (default_msg,)
super().__init__(*args)
[docs]
class PUTRequestError(FreshPyError):
"""This exception is used for generic PUT request errors when there isn't a more specific exception.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "The PUT request did not return a successful response."
custom_msg = "The PUT request failed with the following message:"
if 'status_code' in kwargs or 'message' in kwargs:
if 'status_code' in kwargs:
status_code_msg = f"returned the {kwargs['status_code']} status code"
custom_msg = custom_msg.replace('failed', status_code_msg)
if 'message' in kwargs:
custom_msg = f"{custom_msg} {kwargs['message']}"
else:
custom_msg = custom_msg.split(FOLLOWING_SEGMENT)[0] + "."
args = (custom_msg,)
elif not (args or kwargs) or args[0] is None:
args = (default_msg,)
super().__init__(*args)
####################
# Ticket Exceptions
####################
[docs]
class InvalidFilterLogicError(FreshPyError):
"""This exception is used when an invalid filter logic operator is supplied.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "An invalid filter logic operator was provided."
custom_msg = "The filter logic operator 'X' is invalid."
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
elif 'value' in kwargs:
custom_msg = custom_msg.replace('X', kwargs['value'])
args = (custom_msg,)
super().__init__(*args)
[docs]
class InvalidPredefinedFilterError(FreshPyError):
"""This exception is used when the API query could not be completed due to connection aborts and/or timeouts.
.. version-added:: 1.0.0
"""
def __init__(self, *args, **kwargs):
"""This method defines the default or custom message for the exception."""
default_msg = "An invalid predefined filter was provided."
custom_msg = "The provided filter 'X' is not a valid predefined filter."
if not (args or kwargs) or args[0] is None:
args = (default_msg,)
elif 'value' in kwargs:
custom_msg = custom_msg.replace('X', kwargs['value'])
args = (custom_msg,)
super().__init__(*args)