Skip to content

Require a condition

require_condition() checks a condition and raises an exception when it fails. It saves you from scattering the same if <whatever>: raise Exception(<message>) pattern throughout your code, with a little less repetition.

Basic use

1
2
3
4
5
6
7
8
from buzz import require_condition

# Vanilla python
if not some_condition():
    raise Exception("some_condition failed")

# With py-buzz
require_condition(some_condition(), "some_condition failed")

It is a small bit of syntactic sugar, but it can make functions with lots of checks easier to read.

For a Buzz subclass, the class method binds the exception type:

1
2
3
4
5
6
7
from buzz import Buzz, require_condition

class ConfigError(Buzz):
    pass

require_condition(config_is_valid(), "Invalid configuration", raise_exc_class=ConfigError)
ConfigError.require_condition(config_is_valid(), "Invalid configuration")

Advanced use

Use callbacks to observe both outcomes, and constructor arguments to attach structured context to the failure. The standalone function takes an explicit exception class; a Buzz subclass method binds its own type and builder:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from buzz import Buzz, require_condition


class ConfigException(Exception):
    def __init__(self, message: str, setting: str, *, source: str):
        self.setting = setting
        self.source = source
        super().__init__(message)


def report_failure(exc: Exception) -> None:
    print(f"Configuration check failed: {exc}")


def report_success() -> None:
    print("Configuration is valid")


def check_config(enabled: bool) -> None:
    require_condition(
        enabled,
        "Configuration is disabled",
        raise_exc_class=ConfigException,
        raise_args=["feature flag"],
        raise_kwargs={"source": "startup"},
        do_except=report_failure,
        do_else=report_success,
    )


class ConfigError(Buzz):
    def __init__(self, message: str, setting: str, *, source: str, base_message: str | None = None):
        self.setting = setting
        self.source = source
        super().__init__(message, base_message=base_message)


def check_config_with_buzz(enabled: bool) -> None:
    ConfigError.require_condition(
        enabled,
        "Configuration is disabled",
        raise_args=["feature flag"],
        raise_kwargs={"source": "startup"},
        do_except=report_failure,
        do_else=report_success,
    )

When enabled is false, each function constructs its configured exception with setting="feature flag" and source="startup", calls report_failure with that exception, and then raises it. When it is true, report_success runs and the check returns normally.

exc_builder

A custom builder can adapt an exception whose constructor does not accept the message first. It receives ExcBuilderParams, including the selected exception class, message, positional arguments, and keyword arguments:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from buzz import require_condition
from buzz.tools import ExcBuilderParams


class StatusError(Exception):
    def __init__(self, status_code: int, *, detail: str, source: str):
        self.status_code = status_code
        self.detail = detail
        self.source = source
        super().__init__(detail)


def build_status_error(params: ExcBuilderParams) -> Exception:
    return params.raise_exc_class(
        *params.raise_args,
        detail=params.message,
        **params.raise_kwargs,
    )


require_condition(
    False,
    "The account is inactive",
    raise_exc_class=StatusError,
    raise_args=[403],
    raise_kwargs={"source": "account check"},
    exc_builder=build_status_error,
)

The builder maps the check's message to detail, while raise_args supplies status_code and raise_kwargs supplies source. This example uses a local non-Buzz exception rather than assuming a particular web framework's constructor.

A Buzz subclass binds its own builder for the equivalent class-method call. Override exc_builder on the class to adapt its nonstandard constructor:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from typing_extensions import Self

from buzz import Buzz, require_condition
from buzz.tools import ExcBuilderParams


class AccountError(Buzz):
    def __init__(self, status_code: int, *, detail: str, source: str, base_message: str | None = None):
        self.status_code = status_code
        self.detail = detail
        self.source = source
        super().__init__(detail, base_message=base_message)

    @classmethod
    def exc_builder(cls, params: ExcBuilderParams) -> Self:
        return cls(
            *params.raise_args,
            detail=params.message,
            base_message=params.base_message,
            **params.raise_kwargs,
        )


AccountError.require_condition(
    False,
    "The account is inactive",
    raise_args=[403],
    raise_kwargs={"source": "account check"},
)