Source code for drresult.class_decorators

# Copyright 2024 Ole Kliemann
# SPDX-License-Identifier: MIT

from typing import Any, Callable, Type, List
from drresult.result import Result, Ok
from drresult.function_decorators import returns_result, expects_default, not_expects_default

"""
This module provides a decorator for classes whose constructors might raise exceptions.

Decorators:
    - constructs_as_result: Wraps the construction of a class in a `Result` type.
"""


def make_drresult_constructs_as_result_decorator[
    T
](
    expects: List[Type[BaseException]] = expects_default,
    not_expects: List[Type[BaseException]] = not_expects_default,
) -> Callable[[Type[T]], Type[T]]:
    """Creates a decorator to wrap class constructors in a `Result` type.

    Args:
        expects (List[Type[BaseException]]): List of expected exceptions.
        not_expects (List[Type[BaseException]]): List of unexpected exceptions.

    Returns:
        Callable: A decorator for classes.
    """

    def make_drresult_constructs_as_result_wrapper(cls: Type[T]) -> Type[T]:
        Base = type(cls)  # type: Any

        class Meta(Base):
            @returns_result(expects=expects, not_expects=not_expects)
            def __call__(cls, *args, **kwargs) -> Result[T]:
                return cls.drresult_constructs_as_result_wrapper(*args, **kwargs)

            def drresult_constructs_as_result_wrapper(cls, *args, **kwargs) -> Result[T]:
                return Ok(super(Meta, cls).__call__(*args, **kwargs))

        WrapperBase = cls  # type: Any

        class Wrapper(WrapperBase, metaclass=Meta):
            """Wrapper class to construct instances as a `Result`."""

            pass

        return Wrapper

    return make_drresult_constructs_as_result_wrapper


[docs] def constructs_as_result[T](*decorator_args: Any, **decorator_kwargs: Any) -> Any: """Decorator to wrap class instantiation in a `Result` type. Can be used with or without arguments. Usage: @constructs_as_result class MyClass: ... @constructs_as_result(expects=[ValueError]) class MyClass: ... Args: *decorator_args (Any): Positional arguments. **decorator_kwargs (Any): Keyword arguments. Returns: Any: The decorated class. """ if len(decorator_args) == 1 and callable(decorator_args[0]) and not decorator_kwargs: return make_drresult_constructs_as_result_decorator(expects_default, not_expects_default)( decorator_args[0] ) else: return make_drresult_constructs_as_result_decorator(**decorator_kwargs)