Skip to main content

Raising Exceptions From the Dead by Re-raising Them With New Exception Types

Project description

zombie-py-logo.png

Python 3.11+ Maintenance Code Style: Blue License: MIT codecov Pylint Pylama Mypy

zombie-py

Bringing Raised Exceptions Back From the Dead As New Exceptions.

zombie-py is a Python library that simplifies the process of transforming and re-raising exceptions. It provides a context manager and decorator for handling exceptions, allowing you to define custom transformations for exceptions. zombie-py is designed to make it easier to handle exceptions in Python by providing a simple and flexible way to transform and re-raise exceptions.

Key Features:

  • Easy: Simplifies the process of transforming and re-raising exceptions.
  • Context Manager and Decorator: Provides both context manager and decorator for handling exceptions.
  • Customizable: Allows defining custom transformations for exceptions.
  • Fully Tested: Ensures reliability through comprehensive tests.

Installation

pip install zombie-py

Usage

Example 1: Using as a Context Manager

from zombie import ExceptionTransformation, Reraise

transform = ExceptionTransformation(
        original_exception=KeyError,
        new_exception=ValueError,
    ),

# Using as a context manager with multiple transforms
with Reraise(transform):
    raise KeyError('Original error message')

Example Output

Traceback (most recent call last):
    File "example.py", line 20, in <module>
        raise KeyError('Original error message')
    File "example.py", line 15, in <module>
        raise ValueError('Original error message') from e
ValueError: 'Original error message'

Example 2: Using as a Decorator

from zombie import ExceptionTransformation, Reraise

transforms = [
    ExceptionTransformation(
        original_exception=KeyError,
        new_exception=ValueError,
        error_message='A KeyError occurred',
        raise_from_error=True,
    ),
    ExceptionTransformation(
        original_exception=TypeError,
        new_exception=RuntimeError,
        error_message='A TypeError occurred',
        raise_from_error=True,
    ),
]

# Using as a decorator with multiple transforms
@Reraise(*transforms)
def func():
    raise KeyError('Original error message')

func()

Example Output

Traceback (most recent call last):
    File "example.py", line 20, in <module>
        func()
    File "example.py", line 15, in func
        raise KeyError('Original error message')
KeyError: 'Original error message'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
    File "example.py", line 20, in <module>
        func()
    File "example.py", line 15, in func
        raise ValueError('A KeyError occurred') from e
ValueError: A KeyError occurred

Example 3: Ordering of Exception Transformations

The order in which ExceptionTransformation objects are provided to the Reraise context manager or decorator matters. The transformations are applied sequentially, and the first matching transformation will be used to transform and raise the exception. This means that if multiple transformations could apply to the same exception, the first one in the list will take precedence. For example, consider the following transformations:

from zombie import ExceptionTransformation, Reraise

# Order matters: The first matching transformation will be applied
@Reraise(
    [
        ExceptionTransformation(
            original_exception=KeyError,
            new_exception=ValueError,
            error_message='A KeyError occurred', 
        ),
        ExceptionTransformation(
            original_exception=Exception,
            new_exception=KeyboardInterrupt,
            error_message='An Exception occurred',
        ),
    ]
)
def func():
    raise KeyError('Original error message')

func()
# Raises ValueError with message 'A KeyError occurred'
# Since KeyError is a subclass of Exception, the second transformation will not be applied.

Example Output

Traceback (most recent call last):
  File "zombie.py", line 314, in <module>
    func()
  File "zombie.py", line 213, in wrapper
    _raise_transformed_exception(
  File "zombie.py", line 138, in _raise_transformed_exception
    _transform_and_raise(transform=transform, error=error)
  File "zombie.py", line 109, in _transform_and_raise
    raise transform.new_exception(error_message) from None
ValueError: A KeyError occurred

In this example, even though KeyError is a subclass of Exception, the ExceptionTransformation for Exception will be applied first, transforming the KeyError into a KeyboardInterrupt. If the order were reversed, the KeyError would be transformed into a RuntimeError instead. Therefore, the order of transformations can affect the final exception that is raised.

Advanced Usage Examples for ExceptionTransformation

Using error_message

The error_message parameter allows you to customize the error message of the new exception. You can use a static string or a string.Template to include dynamic content from the original exception. Using the default None will use the original exception's message.

Default Error Message

If the error_message parameter is not provided, the new exception will use the original exception's message.

from zombie import ExceptionTransformation, Reraise

# Define an exception transformation without an error message
transform = ExceptionTransformation(
    original_exception=KeyError,
    new_exception=ValueError,
    raise_from_error=True
)

@Reraise(transform)
def example_function():
    raise KeyError("Original error message")

try:
    example_function()
except Exception as e:
    print(e)  # Output: Original error message

Static Error Message

from zombie.zombie import ExceptionTransformation, Reraise

# Define an exception transformation with a static error message
transform = ExceptionTransformation(
    original_exception=KeyError,
    new_exception=ValueError,
    error_message="A static error message",
    raise_from_error=True
)

@Reraise(transform)
def example_function():
    raise KeyError("Original error message")

try:
    example_function()
except Exception as e:
    print(e)  # Output: A static error message

Dynamic Error Message with string.Template

from zombie import ExceptionTransformation, Reraise
import string

# Define an exception transformation with a dynamic error message
transform = ExceptionTransformation(
    original_exception=KeyError,
    new_exception=ValueError,
    error_message=string.Template("Error: ${original_error_message}"),
    raise_from_error=True
)

@Reraise(transform)
def example_function():
    raise KeyError("Original error message")

try:
    example_function()
except Exception as e:
    print(e)  # Output: Error: Original error message

Using raise_from_error

The raise_from_error parameter determines whether the new exception should be chained from the original exception. If raise_from_error is True, the new exception will include the original exception as its cause. False will raise the new exception without the original exception as its cause. False is the default value.

With raise_from_error=True

from zombie.zombie import ExceptionTransformation, Reraise

# Define an exception transformation with raise_from_error=True
transform = ExceptionTransformation(
    original_exception=KeyError,
    new_exception=ValueError,
    error_message="An error occurred",
    raise_from_error=True
)

@Reraise(transform)
def example_function():
    raise KeyError("Original error message")

example_function()
Example Output
$ python example.py
Traceback (most recent call last):
    File "example.py", line 20, in <module>
        raise KeyError('Original error message')
KeyError: 'Original error message'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
    File "example.py", line 20, in <module>
        raise KeyError('Original error message')
    File "example.py", line 15, in <module>
        raise ValueError('A KeyError occurred') from e
ValueError: A KeyError occurred

With raise_from_error=False (default)

from zombie import ExceptionTransformation, Reraise

# Define an exception transformation with raise_from_error=False
transform = ExceptionTransformation(
    original_exception=KeyError,
    new_exception=ValueError,
    error_message="An error occurred",
    raise_from_error=False
)

@Reraise(transform)
def example_function():
    raise KeyError("Original error message")

example_function()
Example Output
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<path_to_project>/zombie/zombie.py", line 146, in wrapper
        _raise_transformed_exception(*exception_transformations, error=error)
    File "<path_to_project>/zombie/zombie.py", line 116, in _raise_transformed_exception
        _transform_and_raise(transform=transform, error=error)
    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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zombie_py-1.0.tar.gz (9.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zombie_py-1.0-py3-none-any.whl (7.3 kB view details)

Uploaded Python 3

File details

Details for the file zombie_py-1.0.tar.gz.

File metadata

  • Download URL: zombie_py-1.0.tar.gz
  • Upload date:
  • Size: 9.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.9.21

File hashes

Hashes for zombie_py-1.0.tar.gz
Algorithm Hash digest
SHA256 01ce06364768b18f525c9cbf5918e593c097b493854c6063c04a0ed83c7f953e
MD5 6de9e24c520562fa8e57b9c50f53f2fc
BLAKE2b-256 1ca4c80823281dd4655e2eb28351408b8a07ed2ec51568d294ba199eab57732a

See more details on using hashes here.

File details

Details for the file zombie_py-1.0-py3-none-any.whl.

File metadata

  • Download URL: zombie_py-1.0-py3-none-any.whl
  • Upload date:
  • Size: 7.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.9.21

File hashes

Hashes for zombie_py-1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 26dd30d08af4daef2c884b7eed64d7b11cc56d45ef846b0b17c9d1676c0d4ea4
MD5 b2a97c5bfc375c806226989656bf79fb
BLAKE2b-256 8e26bef8bdd4c42376f703f5c05f46e43e6a26aee5f85cf9c681f0276699b89d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page