Source code for paramcheckup.numbers

"""
##### List of functions (alphabetical order) #####

## Functions WITH TESTS ###
- is_between_a_and_b(number, lower, upper, param_name, kind, kind_name, inclusive=True, stacklevel=4, error=True,)
- is_float_or_int(number, param_name, kind, kind_name, stacklevel=4, error=True)
- is_greater_than(number, lower, param_name, kind, kind_name, inclusive=True, stacklevel=4, error=True)
- is_lower_than(number, upper, param_name, kind, kind_name, inclusive=True, stacklevel=4, error=True)
- is_negative(number, param_name, kind, kind_name, stacklevel=4, error=True)
- is_positive(number, param_name, kind, kind_name, stacklevel=4, error=True)


## Functions WITH some TESTS (needs improvements) ###


## Functions WITHOUT tests ###



##### List of CLASS (alphabetical order) #####



Author: Anderson Marcos Dias Canteli <andersonmdcanteli@gmail.com>

Created: October 24, 2023.

Last update: November 15, 2023



"""

##### IMPORTS #####

### Standard ###
import sys

### Third part ###
import numpy as np

### home made ###
from .utils import user_warning
from . import documentation as docs

##### CONSTANTS #####


##### CLASSES #####


##### FUNCTIONS #####
[docs] @docs.docstring_parameter( number=docs.NUMBER["type"], number_desc=docs.NUMBER["description"], lower=docs.LOWER["type"], lower_desc=docs.LOWER["description"], upper=docs.UPPER["type"], upper_desc=docs.UPPER["description"], param_name=docs.PARAM_NAME["type"], param_name_desc=docs.PARAM_NAME["description"], kind=docs.KIND["type"], kind_desc=docs.KIND["description"], kind_name=docs.KIND_NAME["type"], kind_name_desc=docs.KIND_NAME["description"], inclusive=docs.INCLUSIVE["type"], inclusive_desc=docs.INCLUSIVE["description"], stacklevel=docs.STACKLEVEL["type"], stacklevel_desc=docs.STACKLEVEL["description"], error=docs.ERROR["type"], error_desc=docs.ERROR["description"], ) def is_between_a_and_b( number, lower, upper, param_name, kind, kind_name, inclusive=True, stacklevel=4, error=True, ): """This function checks whether a number (`number`) is within the range (open or closed) `lower` and `upper`. Parameters ---------- {number} {number_desc} {lower} {lower_desc} {upper} {upper_desc} {param_name} {param_name_desc} `number`; {kind} {kind_desc} {kind_name} {kind_name_desc} {inclusive} {inclusive_desc} {stacklevel} {stacklevel_desc} {error} {error_desc} Notes ----- If `lower` is greater than `upper`, the function automatically inverts the values to make mathematical sense. Returns ------- output : True If `number` **IN** `[a;b]` (or `(a;b)`) interval; raises : ValueError If `number` **NOT** in `[a;b]` (or `(a;b)`) interval; Examples -------- Checking if the significance level is a number between 0 and 1: >>> from paramcheckup import numbers >>> output = numbers.is_between_a_and_b( number=0, lower=0, upper=1, param_name="alpha", kind="function", kind_name="ttest", stacklevel=3, error=False, ) >>> print(output) True In some cases the lower and upper limits must be opened. To disallow closed ranges, simply pass parameter `inclusive=False`: >>> from paramcheckup import numbers >>> output = numbers.is_between_a_and_b( number=0.0, lower=0, upper=1, param_name="alpha", kind="function", kind_name="ttest", inclusive=False, stacklevel=3, error=False, ) UserWarning at line 3: The value of `alpha` in function `ttest` must be within the range of `0 < alpha < 1`, but it is `0`. Another example with an error being reported, but with `inclusive=True`: >>> from paramcheckup import numbers >>> output = numbers.is_between_a_and_b( number=-0.35, lower=0, upper=1, param_name="alpha", kind="function", kind_name="ttest", stacklevel=3, error=False, ) UserWarning at line 3: The value of `alpha` in function `ttest` must be within the range of `0 <= alpha <= 1`, but it is `-0.35`. """ values = [lower, upper] lower = min(values) upper = max(values) if inclusive is True: if (lower <= number <= upper) is False: user_warning( f"The value of `{param_name}` in {kind} `{kind_name}` must be within the range of `{lower} <= {param_name} <= {upper}`, but it is `{number}`.\n", stacklevel=stacklevel, ) if error is False: sys.exit(1) else: try: raise ValueError("OutofBoundsError") except ValueError: raise else: if (lower < number < upper) is False: user_warning( f"The value of `{param_name}` in {kind} `{kind_name}` must be within the range of `{lower} < {param_name} < {upper}`, but it is `{number}`.\n", stacklevel=stacklevel, ) if error is False: sys.exit(1) else: try: raise ValueError("OutofBoundsError") except ValueError: print() raise return True
[docs] @docs.docstring_parameter( number=docs.NUMBER["type"], number_desc=docs.NUMBER["description"], lower=docs.LOWER["type"], lower_desc=docs.LOWER["description"], param_name=docs.PARAM_NAME["type"], param_name_desc=docs.PARAM_NAME["description"], kind=docs.KIND["type"], kind_desc=docs.KIND["description"], kind_name=docs.KIND_NAME["type"], kind_name_desc=docs.KIND_NAME["description"], inclusive=docs.INCLUSIVE["type"], inclusive_desc=docs.INCLUSIVE["description"], stacklevel=docs.STACKLEVEL["type"], stacklevel_desc=docs.STACKLEVEL["description"], error=docs.ERROR["type"], error_desc=docs.ERROR["description"], ) def is_greater_than( number, lower, param_name, kind, kind_name, inclusive=True, stacklevel=4, error=True ): """This function checks if a `number` is equal (open or closed) or higher than `lower`. Parameters ---------- {number} {number_desc} {lower} {lower_desc} {param_name} {param_name_desc} `number`; {kind} {kind_desc} {kind_name} {kind_name_desc} {inclusive} {inclusive_desc} {stacklevel} {stacklevel_desc} {error} {error_desc} Returns ------- output : True If `number` **IS** greater than lower (or `number` **IS** equal/greater than `lower`); raises : ValueError If `number` is **NOT** greater than lower (or `number` is **NOT** equal/greater than `lower`); Examples -------- >>> from paramcheckup import numbers >>> output = numbers.is_greater_than( number=0.05, lower=0, param_name="alpha", kind="function", kind_name="ttest", inclusive=True, stacklevel=3, error=True, ) >>> print(output) True >>> from paramcheckup import numbers >>> output = numbers.is_greater_than( number=0.00, lower=0, param_name="alpha", kind="function", kind_name="ttest", inclusive=False, stacklevel=3, error=False, ) UserWarning at line 2: The value of `alpha` in function `ttest` must be greater than `0` (`alpha > 0`), but it is `0.0`. >>> from paramcheckup import numbers >>> output = numbers.is_greater_than( number=-0.05, lower=0, param_name="alpha", kind="function", kind_name="ttest", inclusive=True, stacklevel=3, error=False, ) UserWarning at line 2: The value of `alpha` in function `ttest` must be equal or greater than `0` (`alpha >= 0`), but it is `-0.05`. """ if inclusive: if number < lower: user_warning( f"The value of `{param_name}` in {kind} `{kind_name}` must be equal or greater than `{lower}` (`{param_name} >= {lower}`), but it is `{number}`.\n", stacklevel=stacklevel, ) if error is False: sys.exit(1) else: try: raise ValueError("OutofBoundsError") except ValueError: raise else: if number <= lower: user_warning( f"The value of `{param_name}` in {kind} `{kind_name}` must be greater than `{lower}` (`{param_name} > {lower}`), but it is `{number}`.\n", stacklevel=stacklevel, ) if error is False: sys.exit(1) else: try: raise ValueError("OutofBoundsError") except ValueError: raise return True
[docs] @docs.docstring_parameter( number=docs.NUMBER["type"], number_desc=docs.NUMBER["description"], upper=docs.UPPER["type"], upper_desc=docs.UPPER["description"], param_name=docs.PARAM_NAME["type"], param_name_desc=docs.PARAM_NAME["description"], kind=docs.KIND["type"], kind_desc=docs.KIND["description"], kind_name=docs.KIND_NAME["type"], kind_name_desc=docs.KIND_NAME["description"], inclusive=docs.INCLUSIVE["type"], inclusive_desc=docs.INCLUSIVE["description"], stacklevel=docs.STACKLEVEL["type"], stacklevel_desc=docs.STACKLEVEL["description"], error=docs.ERROR["type"], error_desc=docs.ERROR["description"], ) def is_lower_than( number, upper, param_name, kind, kind_name, inclusive=True, stacklevel=4, error=True, ): """This function checks if a `number` is equal (open or closed) or lower than `upper`. Parameters ---------- {number} {number_desc} {upper} {upper_desc} {param_name} {param_name_desc} `number`; {kind} {kind_desc} {kind_name} {kind_name_desc} {inclusive} {inclusive_desc} {stacklevel} {stacklevel_desc} {error} {error_desc} Returns ------- output : True If `numer` **IS** lower than `upper` (or `number` **IS** lower/equal than `upper`); raises : ValueError If `numer` is **NOT** lower than `upper` (or `number` is **NOT** lower/equal than `upper`); Examples -------- >>> from paramcheckup import numbers >>> output = numbers.is_lower_than( number=0.05, upper=1, param_name="alpha", kind="function", kind_name="ttest", inclusive=True, stacklevel=3, error=False, ) >>> print(output) True >>> from paramcheckup import numbers >>> output = numbers.is_lower_than( number=1, upper=1, param_name="alpha", kind="function", kind_name="ttest", inclusive=False, stacklevel=3, error=False, ) UserWarning at line 2: The value of `alpha` in function `ttest` must be lower than `1` (`alpha < 1`), but it is `1`. >>> from paramcheckup import numbers >>> output = numbers.is_lower_than( number=1.05, upper=1, param_name="alpha", kind="function", kind_name="ttest", inclusive=True, stacklevel=3, error=False, ) UserWarning at line 2: The value of `alpha` in function `ttest` must be equal or lower than `1` (`alpha <= 1`), but it is `1.05`. """ if inclusive: if number > upper: user_warning( f"The value of `{param_name}` in {kind} `{kind_name}` must be equal or lower than `{upper}` (`{param_name} <= {upper}`), but it is `{number}`.\n", stacklevel=stacklevel, ) if error is False: sys.exit(1) else: try: raise ValueError("OutofBoundsError") except ValueError: raise else: if number >= upper: user_warning( f"The value of `{param_name}` in {kind} `{kind_name}` must be lower than `{upper}` (`{param_name} < {upper}`), but it is `{number}`.\n", stacklevel=stacklevel, ) if error is False: sys.exit(1) else: try: raise ValueError("OutofBoundsError") except ValueError: raise return True
[docs] @docs.docstring_parameter( number=docs.NUMBER["type"], number_desc=docs.NUMBER["description"], param_name=docs.PARAM_NAME["type"], param_name_desc=docs.PARAM_NAME["description"], kind=docs.KIND["type"], kind_desc=docs.KIND["description"], kind_name=docs.KIND_NAME["type"], kind_name_desc=docs.KIND_NAME["description"], stacklevel=docs.STACKLEVEL["type"], stacklevel_desc=docs.STACKLEVEL["description"], error=docs.ERROR["type"], error_desc=docs.ERROR["description"], ) def is_float_or_int(number, param_name, kind, kind_name, stacklevel=4, error=True): """This function checks whether a variable `value` is of the `int` or `float` type. Parameters ---------- {number} {number_desc} {param_name} {param_name_desc} {kind} {kind_desc} {kind_name} {kind_name_desc} {stacklevel} {stacklevel_desc} {error} {error_desc} Returns ------- Output : True If variable `number` **IS** of the `int` or `float` type; raises : TypeError If variable `number` is **NOT** of the `int` or `float` type; Notes ----- The following types are considered to be `True`: * `int`; * `float`; * `np.floating`; * `np.integer`; * `np.uint`; Examples -------- >>> from paramcheckup import numbers >>> result = numbers.is_float_or_int( number=2, param_name="hypotenuse", kind="function", kind_name="pitagoras", stacklevel=3, error=True, ) >>> print(result) True >>> from paramcheckup import numbers >>> result = numbers.is_float_or_int( number="2", param_name="hypotenuse", kind="function", kind_name="pitagoras", stacklevel=3, error=False, ) UserWarning at line 2: The `hypotenuse` in function `pitagoras` must be of type `int` or `float`, but its type is `str`. """ if isinstance(number, (int, np.uint, np.integer, float, np.floating)) is False: user_warning( f"The `{param_name}` in {kind} `{kind_name}` must be of type `int` or `float`, but its type is `{type(number).__name__}`.\n", stacklevel=stacklevel, ) if error is False: sys.exit(1) else: try: raise TypeError("NotNumberError") except TypeError: raise else: return True
[docs] @docs.docstring_parameter( number=docs.NUMBER["type"], number_desc=docs.NUMBER["description"], param_name=docs.PARAM_NAME["type"], param_name_desc=docs.PARAM_NAME["description"], kind=docs.KIND["type"], kind_desc=docs.KIND["description"], kind_name=docs.KIND_NAME["type"], kind_name_desc=docs.KIND_NAME["description"], stacklevel=docs.STACKLEVEL["type"], stacklevel_desc=docs.STACKLEVEL["description"], error=docs.ERROR["type"], error_desc=docs.ERROR["description"], ) def is_negative(number, param_name, kind, kind_name, stacklevel=4, error=True): """This function checks whether `number` is a negative number (lower than zero, not included). Parameters ---------- {number} {number_desc} {param_name} {param_name_desc} {kind} {kind_desc} {kind_name} {kind_name_desc} {stacklevel} {stacklevel_desc} {error} {error_desc} Returns ------- output : True If `number` **IS** negative; ValueError If `number` is **NOT** negative; Examples -------- >>> from paramcheckup import numbers >>> result = numbers.is_negative( number=-10, param_name="hypotenuse", kind="function", kind_name="pitagoras", stacklevel=3, error=True, ) >>> print(result) True >>> from paramcheckup import numbers >>> result = numbers.is_negative( number=0, param_name="hypotenuse", kind="function", kind_name="pitagoras", stacklevel=3, error=False, ) UserWarning at line 2: The `hypotenuse` in function `pitagoras` must be a negative number, but it is equal to `0`. >>> from paramcheckup import numbers >>> result = numbers.is_negative( number=3.1416, param_name="hypotenuse", kind="function", kind_name="pitagoras", stacklevel=3, error=False, ) UserWarning at line 2: The `hypotenuse` in function `pitagoras` must be a negative number, but it is equal to `3.1416`. """ if number >= 0: user_warning( f"The `{param_name}` in {kind} `{kind_name}` must be a negative number, but it is equal to `{number}`.\n", stacklevel=stacklevel, ) if error is False: sys.exit(1) else: try: raise ValueError("NotNegativeError") except ValueError: raise return True
[docs] @docs.docstring_parameter( number=docs.NUMBER["type"], number_desc=docs.NUMBER["description"], param_name=docs.PARAM_NAME["type"], param_name_desc=docs.PARAM_NAME["description"], kind=docs.KIND["type"], kind_desc=docs.KIND["description"], kind_name=docs.KIND_NAME["type"], kind_name_desc=docs.KIND_NAME["description"], stacklevel=docs.STACKLEVEL["type"], stacklevel_desc=docs.STACKLEVEL["description"], error=docs.ERROR["type"], error_desc=docs.ERROR["description"], ) def is_positive(number, param_name, kind, kind_name, stacklevel=4, error=True): """This function checks whether `number` is a positive number (lower than zero, not included). Parameters ---------- {number} {number_desc} {param_name} {param_name_desc} {kind} {kind_desc} {kind_name} {kind_name_desc} {stacklevel} {stacklevel_desc} {error} {error_desc} Returns ------- True If variable *value* **IS** positive; ValueError If variable *value* is **NOT** positive; Examples -------- >>> from paramcheckup import numbers >>> result = numbers.is_positive( number=3.1416, param_name="hypotenuse", kind="function", kind_name="pitagoras", stacklevel=3, error=False, ) >>> print(result) True >>> from paramcheckup import numbers >>> result = numbers.is_positive( number=0, param_name="hypotenuse", kind="function", kind_name="pitagoras", stacklevel=3, error=False, ) UserWarning at line 2: The `hypotenuse` in function `pitagoras` must be a positive number, but it is equal to `0`. >>> from paramcheckup import numbers >>> result = numbers.is_positive( number=-273.15, param_name="hypotenuse", kind="function", kind_name="pitagoras", stacklevel=3, error=False, ) UserWarning at line 2: The `hypotenuse` in function `pitagoras` must be a positive number, but it is equal to `-273.15`. """ if number <= 0: user_warning( f"The `{param_name}` in {kind} `{kind_name}` must be a positive number, but it is equal to `{number}`.\n", stacklevel=stacklevel, ) if error is False: sys.exit(1) else: try: raise ValueError("NotPositiveError") except ValueError: raise return True