Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: @validator now catches Exception #254

Merged
merged 2 commits into from
Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ True

## Resources

- [Documentation](https://python-validators.github.io/)
- [Documentation](https://python-validators.github.io/validators/)
- [Issue Tracker](https://github.com/python-validators/validators/issues)
- [Security](https://github.com/python-validators/validators/blob/master/SECURITY.md)
- [Code](https://github.com/python-validators/validators/)
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ True

## Resources

- [Documentation](https://python-validators.github.io/)
- [Documentation](https://python-validators.github.io/validators/)
- [Issue Tracker](https://github.com/python-validators/validators/issues)
- [Security](https://github.com/python-validators/validators/blob/master/SECURITY.md)
- [Code](https://github.com/python-validators/validators/)
Expand Down
2 changes: 1 addition & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
site_name: "validators"
site_description: "Automatic documentation from sources, for MkDocs."
site_url: "https://python-validators.github.io/"
site_url: "https://python-validators.github.io/validators/"
repo_url: "https://github.com/python-validators/validators"
edit_uri: "tree/master/docs/"
repo_name: "validators/validators"
Expand Down
227 changes: 99 additions & 128 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ classifiers = [
"Programming Language :: Python :: Implementation :: CPython",
"Topic :: Software Development :: Libraries :: Python Modules",
]
include = ["CHANGES.md", "docs/*"]
include = ["CHANGES.md", "docs/*", "validators/py.typed"]

[tool.poetry.dependencies]
python = "^3.8"
Expand Down Expand Up @@ -50,7 +50,7 @@ black = "^23.1.0"
flake8 = "^5.0.4"
flake8-docstrings = "^1.7.0"
isort = "^5.12.0"
pyright = "^1.1.299"
pyright = "^1.1.300"

[build-system]
requires = ["poetry-core"]
Expand Down
27 changes: 5 additions & 22 deletions tests/test_between.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,19 @@ def test_returns_true_on_valid_range(value: T, min_val: T, max_val: T):
assert between(value, min_val=min_val, max_val=max_val)


@pytest.mark.parametrize(
("value", "min_val", "max_val"),
[(12, 13, 12), (12, None, None)],
)
def test_raises_assertion_error_for_invalid_args(value: T, min_val: T, max_val: T):
"""Test raises assertion error for invalid args."""
with pytest.raises(AssertionError):
assert between(value, min_val=min_val, max_val=max_val)


@pytest.mark.parametrize(
("value", "min_val", "max_val"),
[
(12, 13, 14),
(12, None, 11),
(12, None, None),
(12, 13, None),
(12, "13.5", datetime(1970, 1, 1)),
("12", 20.5, "None"),
(datetime(1970, 1, 1), 20, "string"),
(30, 40, "string"),
],
)
def test_raises_type_error_for_invalid_args(value: T, min_val: T, max_val: T):
"""Test raises type error for invalid args."""
with pytest.raises(TypeError):
assert between(value, min_val=min_val, max_val=max_val)


@pytest.mark.parametrize(
("value", "min_val", "max_val"),
[(12, 13, 14), (12, None, 11), (12, 13, None)],
)
def test_returns_failed_validation_on_invalid_range(value: T, min_val: T, max_val: T):
"""Test returns failed validation on invalid range."""
result = between(value, min_val=min_val, max_val=max_val)
assert isinstance(result, ValidationFailure)
assert isinstance(between(value, min_val=min_val, max_val=max_val), ValidationFailure)
12 changes: 1 addition & 11 deletions tests/test_length.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,7 @@ def test_returns_true_on_valid_length(value: str, min_val: int, max_val: int):

@pytest.mark.parametrize(
("value", "min_val", "max_val"),
[("something", 14, 12), ("something", -10, -20), ("something", 0, -2)],
)
def test_raises_assertion_error_for_invalid_args(value: str, min_val: int, max_val: int):
"""Test raises assertion error for invalid args."""
with pytest.raises(AssertionError):
assert length(value, min_val=min_val, max_val=max_val)


@pytest.mark.parametrize(
("value", "min_val", "max_val"),
[("something", 13, 14), ("something", 0, 6), ("something", 14, 20)],
[("something", 14, 12), ("something", -10, -20), ("something", 0, -2), ("something", 13, 14)],
)
def test_returns_failed_validation_on_invalid_range(value: str, min_val: int, max_val: int):
"""Test returns failed validation on invalid range."""
Expand Down
27 changes: 15 additions & 12 deletions validators/between.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def between(
If `value` is not in between the given conditions.

Raises:
AssertionError: If both `min_val` and `max_val` are `None`,
ValueError: If both `min_val` and `max_val` are `None`,
or if `min_val` is greater than `max_val`.
TypeError: If there's a type mismatch before comparison.

Expand All @@ -68,29 +68,32 @@ def between(

> *New in version 0.2.0*.
"""
if not value:
return False

if min_val is None and max_val is None:
raise AssertionError("At least one of either `min_val` or `max_val` must be specified")
raise ValueError("At least one of either `min_val` or `max_val` must be specified")

if max_val is None:
max_val = AbsMax()
if min_val is None:
min_val = AbsMin()

if isinstance(min_val, AbsMin):
if type(value) is not type(max_val):
raise TypeError("`value` and `max_val` must be of same type")
return min_val <= value <= max_val
if type(value) is type(max_val):
return min_val <= value <= max_val
raise TypeError("`value` and `max_val` must be of same type")

if isinstance(max_val, AbsMax):
if type(value) is not type(min_val):
raise TypeError("`value` and `min_val` must be of same type")
return min_val <= value <= max_val
if type(value) is type(min_val):
return min_val <= value <= max_val
raise TypeError("`value` and `min_val` must be of same type")

if type(min_val) is type(max_val):
if min_val > max_val:
raise AssertionError("`min_val` cannot be more than `max_val`")
if type(value) is not type(min_val): # or type(max_val):
raise TypeError("`value` and (`min_val` or `max_val`) must be of same type")
return min_val <= value <= max_val
raise ValueError("`min_val` cannot be more than `max_val`")
if type(value) is type(min_val): # or is type(max_val)
return min_val <= value <= max_val
raise TypeError("`value` and (`min_val` or `max_val`) must be of same type")

raise TypeError("`value` and `min_val` and `max_val` must be of same type")
Empty file added validators/py.typed
Empty file.
19 changes: 12 additions & 7 deletions validators/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
class ValidationFailure(Exception):
"""Exception class when validation failure occurs."""

def __init__(self, function: Callable[..., Any], arg_dict: Dict[str, Any]):
def __init__(self, function: Callable[..., Any], arg_dict: Dict[str, Any], message: str = ""):
"""Initialize Validation Failure."""
if message:
self.reason = message
self.func = function
self.__dict__.update(arg_dict)

Expand Down Expand Up @@ -60,7 +62,7 @@ def validator(func: Callable[..., Any]):
Function which is to be decorated.

Returns:
(Callable[..., ValidationFailure | Literal[True])):
(Callable[..., ValidationFailure | Literal[True]]):
A decorator which returns either `ValidationFailure`
or `Literal[True]`.

Expand All @@ -69,10 +71,13 @@ def validator(func: Callable[..., Any]):

@wraps(func)
def wrapper(*args: Any, **kwargs: Any):
return (
True
if func(*args, **kwargs)
else ValidationFailure(func, _func_args_as_dict(func, *args, **kwargs))
)
try:
return (
True
if func(*args, **kwargs)
else ValidationFailure(func, _func_args_as_dict(func, *args, **kwargs))
)
except Exception as exp:
return ValidationFailure(func, _func_args_as_dict(func, *args, **kwargs), str(exp))

return wrapper