Source code for covsirphy.util.error

from copy import deepcopy
from covsirphy.util.config import config


[docs] def deprecate(old, new=None, version=None, ref=None): """ Decorator to raise deprecation warning. Args: old (str): description of the old method/function new (str or None): description of the new method/function version (str or None): version number, like 2.7.3-alpha ref (str or None): reference URL of the new method/function """ def _deprecate(func): def wrapper(*args, **kwargs): version_str = "." if version is None else f", version >= {version}." message = "" if ref is None else f" Refer to {ref}." if new is None: comment = f"{old} was deprecated{version_str}{message}" else: comment = f"Please use {new} rather than {old}{version_str}{message}" config.warning(message=comment, category=DeprecationWarning) return func(*args, **kwargs) return wrapper return _deprecate
[docs] def experimental(name, version): """ Decorator to raise ExperimentalWarning because the method/function is experimental. Args: name (str): description of the method/function version (str): version number, like 2.7.3-alpha """ def _experimental(func): def wrapper(*args, **kwargs): comment = f"{name} can be used from {version}, but this is experimental." \ "Its name and arguments may be changed later." config.warning(message=comment, category=ExperimentalWarning) return func(*args, **kwargs) return wrapper return _experimental
class _BaseWarning(Warning): """Basic class of warning. """ pass
[docs] class ExperimentalWarning(Warning): """Class to explain the method/function is experimental and its name, features and arguments may changed later. """ pass
class _BaseException(Exception): """Basic class of exception. Args: message (str): main message of error, should be set in child classes details (str or None): details of error log (str): description used by logger """ def __init__(self, message, details=None, log="exception raised"): config.error(log) self._message = str(message) self._details = "" if details is None else f" {details}." def __str__(self): return f"{self._message}. {self._details}" class _ValidationError(_BaseException): """Basic class of exception raised when validation. Args: name (str): name of the target message (str): main message of error, should be set in child classes details (str or None): details of error log (str): description used by logger """ def __init__(self, name, message, details=None): log = f"validation of {name} failed" super().__init__(message=message, details=details, log=log)
[docs] class NotIncludedError(_ValidationError): """Error when a necessary key was not included in a container. Args: key_name (str): key name container_name (str): name of the container details (str or None): details of error """ def __init__(self, key_name, container_name, details=None): message = f"'{key_name}' was not included in the '{container_name}'" super().__init__(name=key_name, message=message, details=details)
[docs] class NAFoundError(_ValidationError): """Error when NA values are included un-expectedly. Args: name (str): name of the target value (str or None): value of the target details (str or None): details of error """ def __init__(self, name, value=None, details=None): message = f"'{name}' has NA(s) un-expectedly" if value is not None: message += f", '{value}'" super().__init__(name=name, message=message, details=details)
[docs] class NotEnoughDataError(_ValidationError): """Error when we do not have enough data for analysis. Args: name (str): name of the target value (str): value of the target required_n (int): required number of records details (str or None): details of error """ def __init__(self, name, value, required_n, details=None): message = f"We need more than {required_n} records, but '{name}' has only {len(value)} records at this time" super().__init__(name=name, message=message, details=details)
[docs] class UnExpectedNoneError(_ValidationError): """Error when a value is None un-expectedly. Args: name (str): name of the target details (str or None): details of error """ def __init__(self, name, details=None): message = f"'{name}' is None un-expectedly" super().__init__(name=name, message=message, details=details)
[docs] class NotNoneError(_ValidationError): """Error when a value must be None but not None un-expectedly. Args: name (str): name of the target value (str): value of the target details (str or None): details of error """ def __init__(self, name, value, details=None): message = f"'{name}' must be None, but has value '{value}'" super().__init__(name=name, message=message, details=details)
[docs] class UnExecutedError(_BaseException): """ Error when we have unexecuted methods that we need to run in advance. Args: name (str): method name to run in advance details (str or None): details of error """ def __init__(self, name, details=None): message = f"Please execute {name} in advance" log = f"{name} not executed" super().__init__(message=message, details=details, log=log)
[docs] class NotRegisteredError(UnExecutedError): """ Error when no records have been registered yet. """ pass
[docs] class NotSubclassError(_ValidationError): """Error when an object is not a subclass of the parent class un-expectedly. Args: name (str): name of the target target (object): target object parent (object): expected parent class details (str or None): details of error """ def __init__(self, name, target, parent, details=None): message = f"'{name}' must be a sub-class of {parent}, but {type(target)} was applied" super().__init__(name=name, message=message, details=details)
[docs] class UnExpectedTypeError(_ValidationError): """Error when an object cannot be converted to an instance un-expectedly. Args: name (str): name of the target target (object): target object expected (object): expected type details (str or None): details of error """ def __init__(self, name, target, expected, details=None): message = f"We could not convert '{name}' to an instance of {expected} because that of {type(target)} was applied" super().__init__(name=name, message=message, details=details)
[docs] class EmptyError(_ValidationError): """Error when the dataframe is empty un-expectedly. Args: name (str): name of the target details (str or None): details of error """ def __init__(self, name, details=None): message = f"'Empty dataframe/series was applied as {name}' un-expectedly" super().__init__(name=name, message=message, details=details)
[docs] class UnExpectedValueRangeError(_ValidationError): """Error when the value is out of value range. Args: name (str): name of the target target (object): target object value_range (tuple(int or None, int or None)): value range, None means un-specified details (str or None): details of error """ def __init__(self, name, target, value_range, details=None): _min, _max = value_range if _min is None: s = "is not in the expected value range" if _max is None else f"must be under or equal to {_max}" else: s = f"must be over or equal to {_min}" if _max is None else f"is not in the expected value range ({_min}, {_max})" message = f"'{name}' {s}, but {target} was applied" super().__init__(name=name, message=message, details=details)
[docs] class UnExpectedValueError(_ValidationError): """ Error when unexpected value was applied as the value of an argument. Args: name (str): argument name value (object): value user applied candidates (list[object]): candidates of the argument details (str or None): details of error """ def __init__(self, name, value, candidates, details=None): c_str = ", ".join(candidates) message = f"'{name}' must be selected from [{c_str}], but {value} was applied" super().__init__(name=name, message=message, details=details)
[docs] class UnExpectedLengthError(_ValidationError): """ Error when a sequence has un-expended length. Args: name (str): argument name value (object): value user applied length (int): length of the sequence details (str or None): details of error """ def __init__(self, name, value, length, details=None): message = f"The length of '{name}' must be {length}, but {len(value)} was applied" super().__init__(name=name, message=message, details=details)
[docs] class SubsetNotFoundError(_BaseException): """Error when subset was failed with specified arguments. Args: geo (tuple(list[str] or tuple(str) or str) or str or None): location names to filter or None country (str): country name country_alias (str or None): country name used in the dataset province (str or None): province name start_date (str or None): start date, like 22Jan2020 end_date (str or None): end date, like 01Feb2020 date (str or None): specified date, like 22Jan2020 details (str or None): details of error """ def __init__(self, geo=None, country=None, country_alias=None, province=None, start_date=None, end_date=None, date=None, details=None): self.area = self._area(geo, country, country_alias, province) self.date = self._date(start_date, end_date, date) message = f"No records in {self.area}{self.date} were found" log = "data subsetting failed" super().__init__(message=message, details=details, log=log) @staticmethod def _area(geo, country, country_alias, province): """ Error when subset was failed with specified arguments. Args: geo (tuple(list[str] or tuple(str) or str) or str or None): location names to filter or None country (str): country name country_alias (str or None): country name used in the dataset province (str or None): province name Returns: str: area name """ if geo is None and country is None: return "the world" if geo is not None: geo_converted = deepcopy(geo) elif province is None: geo_converted = (country if country_alias is None else f"{country} ({country_alias})",) else: geo_converted = (country if country_alias is None else f"{country} ({country_alias})", province) names = [ info if isinstance(info, str) else "-" if info is None else "_".join(list(info)) for info in ([geo_converted] if isinstance(geo_converted, str) else geo_converted)] return "/".join(names[::-1]) @staticmethod def _date(start_date, end_date, date): """ Error when subset was failed with specified arguments. Args: start_date (str or None): start date, like 22Jan2020 end_date (str or None): end date, like 01Feb2020 date (str or None): specified date, like 22Jan2020 """ if date is not None: return f" on {date}" start_str = "" if start_date is None else f" from {start_date}" end_str = "" if end_date is None else f" to {end_date}" return f"{start_str}{end_str}"
[docs] class ScenarioNotFoundError(_BaseException): """Error when unregistered scenario name was specified. Args: name (str): scenario name details (str or None): details of error """ def __init__(self, name, details=None): message = f"{name} scenario is not registered" log = "scenario selection failed" super().__init__(message=message, details=details, log=log)