Skip to content

Tybruno patch 1 #10

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

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
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 @@ -297,4 +297,4 @@ Traceback (most recent call last):
File "<path_to_project>/zombie/zombie.py", line 85, in _transform_and_raise
raise transform.new_exception(error_message) from None
ValueError: An error occurred
```
```
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
setup,
)

__version__ = 'v1.2'
__version__ = 'v1.3'
__author__ = 'Tyler Bruno'
DESCRIPTION = 'Raising Exceptions From the Dead by Re-raising Them With New Exception \
Types'
Expand Down
10 changes: 7 additions & 3 deletions tests/test_zombie.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ def test_repr(self):


class TestTransformAndRaise:
def test_bad_init(self):
with pytest.raises(TypeError):
Reraise(1)

def test_transform_and_raise_with_template(self):
transform = ExceptionTransformation(
original_exception=KeyError,
Expand Down Expand Up @@ -79,15 +83,15 @@ def test_raise_transformed_exception(self):
)
with pytest.raises(ValueError) as exc_info:
_raise_transformed_exception(
transform, error=KeyError('Original error message')
[transform], error=KeyError('Original error message')
)
assert str(exc_info.value) == 'An error occurred'
assert exc_info.value.__cause__.__class__ == KeyError

def test_no_transformation_found(self, caplog):
with pytest.raises(KeyError) as exc_info:
_raise_transformed_exception(
error=KeyError('Original error message')
[], error=KeyError('Original error message')
)
assert str(exc_info.value) == "'Original error message'"

Expand All @@ -101,7 +105,7 @@ def test_reraise_decorator(self):
raise_from_error=True,
)

@_reraise_decorator(transform)
@_reraise_decorator([transform])
def func():
raise KeyError('Original error message')

Expand Down
65 changes: 35 additions & 30 deletions zombie/zombie.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@

import logging
import string
import typing
import functools
from typing import Type, Iterable, Any, Union, Callable, Tuple

_LOG = logging.getLogger(__name__)

Expand All @@ -38,8 +38,10 @@ class ExceptionTransformation:
error_message (typing.Optional[typing.Union[str, string.Template]]):
The error message to use in the new exception. If a string
template is provided, it will be substituted with the original
error message. If the default `None` provided, the original error
message will be used.
error message. For example, you can use
`string.Template("$original_error_message")` to include the
original error message in the new exception. If the default
is provided, the original error message will be used.
raise_from_error (bool): Whether to chain the new exception from the
original exception. If `True`, the new exception will be chained
from the original exception. If `False`, the new exception will
Expand All @@ -48,9 +50,11 @@ class ExceptionTransformation:

def __init__(
self,
original_exception: typing.Type[BaseException],
new_exception: typing.Type[BaseException],
error_message: str | string.Template | None = None,
original_exception: Type[BaseException],
new_exception: Type[BaseException],
error_message: Union[string.Template, str] = string.Template(
'$original_error_message'
),
raise_from_error: bool = False,
):
self.original_exception = original_exception
Expand Down Expand Up @@ -110,7 +114,7 @@ def _transform_and_raise(


def _raise_transformed_exception(
*exception_transformations: ExceptionTransformation,
exception_transformations: Iterable[ExceptionTransformation],
error: BaseException,
) -> None:
"""Transforms and raises an exception based on provided exception
Expand All @@ -123,7 +127,7 @@ def _raise_transformed_exception(
exception specified in the transformation.

Args:
*exception_transformations (ExceptionTransformation): Variable number
exception_transformations (Iterable[ExceptionTransformation]): Variable number
of `ExceptionTransformation` objects that define how to transform
and raise exceptions.
error (BaseException): The original exception that needs to be
Expand All @@ -141,8 +145,8 @@ def _raise_transformed_exception(


def _reraise_decorator(
*exception_transformations: ExceptionTransformation,
) -> typing.Callable:
exception_transformations: Iterable[ExceptionTransformation],
) -> Callable:
"""Decorator to apply exception transformations to a function.

This decorator applies a collection of `ExceptionTransformation` objects
Expand All @@ -153,15 +157,15 @@ def _reraise_decorator(
transformation.

Args:
*exception_transformations (ExceptionTransformation): Variable number
exception_transformations (Iterable[ExceptionTransformation]): Variable number
of `ExceptionTransformation` objects that define how to transform
and raise exceptions.

Returns:
typing.Callable: The decorated function with exception transformations applied.
"""

def decorator(callable_: typing.Callable) -> typing.Callable:
def decorator(callable_: Callable) -> Callable:
"""Decorator function to apply exception transformations.

This decorator function applies the exception transformations to the
Expand All @@ -184,7 +188,7 @@ def decorator(callable_: typing.Callable) -> typing.Callable:
"""

@functools.wraps(callable_)
def wrapper(*args, **kwargs) -> typing.Any:
def wrapper(*args, **kwargs) -> Any:
"""Wrapper function to apply exception transformations.

This wrapper function applies the exception transformations to the
Expand All @@ -211,7 +215,7 @@ def wrapper(*args, **kwargs) -> typing.Any:
# pylint: disable=broad-except
except BaseException as error:
_raise_transformed_exception(
*exception_transformations, error=error
exception_transformations, error=error
)
return result

Expand All @@ -225,8 +229,8 @@ class Reraise:
transformations.

Args:
exception_transformations (typing.Union[ExceptionTransformation,
typing.Sequence[ExceptionTransformation]]):
exception_transformations (Union[ExceptionTransformation,
Iterable[ExceptionTransformation]]):
A single `ExceptionTransformation` object or a sequence of
`ExceptionTransformation` objects that define
how to transform and raise exceptions.
Expand All @@ -235,42 +239,43 @@ class Reraise:
def __init__(
self,
exception_transformations: ExceptionTransformation
| typing.Sequence[ExceptionTransformation],
| Iterable[ExceptionTransformation],
):
# Store the exception transformations as a tuple
self.exception_transformations: tuple[ExceptionTransformation, ...]

# Check if a single ExceptionTransformation object is provided
self.exception_transformations: Tuple[ExceptionTransformation, ...]
if isinstance(exception_transformations, ExceptionTransformation):
# Convert the single object to a tuple
self.exception_transformations = (exception_transformations,)
else:
# Convert the sequence of ExceptionTransformation objects to a tuple
elif isinstance(exception_transformations, Iterable):
self.exception_transformations = tuple(exception_transformations)
else:
raise TypeError(
'exception_transformations must be an `ExceptionTransformation`'
' object or an iterable of `ExceptionTransformation` objects.'
)

def __enter__(self):
return self

def __exit__(
self,
exc_type: typing.Type[BaseException] | None,
exc_type: Type[BaseException] | None,
exc_value: BaseException,
traceback: typing.Any | None,
traceback: Any | None,
):
if exc_value is None:
# No exception to handle, return False to indicate normal exit
return False
error = exc_value
# Transform and raise the exception based on the provided transformations
_raise_transformed_exception(
*self.exception_transformations, error=error
self.exception_transformations, error=error
)
# Return False to indicate that the exception was not handled here
return False

def decorate(self, callable_: typing.Callable) -> typing.Callable:
def decorate(self, callable_: Callable) -> Callable:
"""Decorates a callable with exception transformations.

self,
This method decorates a function with exception transformations using
the `_reraise_decorator` function. The decorated function will apply
the exception transformations to the function when it raises an
Expand All @@ -283,11 +288,11 @@ def decorate(self, callable_: typing.Callable) -> typing.Callable:
typing.Callable: The decorated function with exception
transformations applied.
"""
wrapped_callable = _reraise_decorator(*self.exception_transformations)(
wrapped_callable = _reraise_decorator(self.exception_transformations)(
callable_
)
return wrapped_callable

def __call__(self, func: typing.Callable) -> typing.Callable:
def __call__(self, func: Callable) -> Callable:
wrapped_callable = self.decorate(func)
return wrapped_callable
Loading