# apfel.expr.affirm

*module*

The expression form of [:python `assert`](https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement),
and related helper functions.

Also see [:rust `assert!`](https://doc.rust-lang.org/std/macro.assert.html).

## Usage

[`affirm`][apfel.expr.affirm.affirm] allows asserting a value according to a predicate,
returning the value if the assertion is satisfied,
or raising an `AssertionError` with detailed information if not.

Similar to the builtin [:python `assert`](https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement),
the `affirm` function will be a no-op when Python is run with optimizations (the [:python `-O` flag](https://docs.python.org/3/using/cmdline.html#cmdoption-O), or setting [:python `__debug__`](https://docs.python.org/3/library/constants.html#debug__) to `False`).

> **Tip**
>
> Specifically, the `AssertionError` message will include the full expression passed to `affirm`,
> not just the evaluated value.
> Different predicates can customize the error message to provide more context.
> 
> ```python
> >>> affirm(operator.mul(2, 3), lambda x: x % 2)
> AssertionError: `operator.mul(2, 3)` evals to 6, which does not satisfy `lambda x: x % 2`.
> >>> affirm(1 or None, type[bool, str])
> AssertionError: `1 or None` evals to 1, which is of type int, expected one of [bool, str].
> ```

Some available forms of predicates:

- **Unspecified or `None`**: evaluate the truthiness of the value.
  ```python
  affirm(1)  # OK, 1
  affirm(0)  # raises AssertionError
  ```
- **Callable**: a function that takes the value and returns a boolean.
  If a `lambda` function is used, its source code will be included in the error message.
  ```python
  affirm(5, lambda x: x > 0)   # OK, 5
  affirm(-3, lambda x: x > 0)  # raises AssertionError
  ```
- **An [`AffirmPredicate`][apfel.expr.affirm.AffirmPredicate]**: a more complex predicate that can customize the failure message.
  ```python
  affirm(True, type[int])  # OK, True (bool is a subclass of int)
  affirm(True, type[str])  # raises AssertionError
  ```
- **Boolean**: an expression that is directly evaluated to a boolean.
  Any value that can be converted to boolean is accepted.
  ```python
  affirm(False, True)    # OK, False
  affirm(True, False)    # raises AssertionError
  ```

> **Tip**
>
> If you want to assert a value is not `None`, which is a much more common use case,
> use the [`apfel.not_none`][apfel.core.common.not_none] function instead.
> 
> If you do not want an exception to be raised, use [`apfel.container.Maybe`][apfel.container.maybe.Maybe]:
> ```python
> just(value).filter(predicate)
> ```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/expr/affirm.py#L1-L1)

## apfel.expr.affirm.U

*attribute* · *module attribute*

```python
U = TypeVar('U', covariant=False, contravariant=False)
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/expr/affirm.py#L6-L6)

## apfel.expr.affirm.AffirmPredicate

*class*

```python
class AffirmPredicate(ABCDispatch)
```

Bases: `apfel.core.dispatch.ABCDispatch`

An abstract base class for complex predicates within the `affirm` function.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/expr/affirm.py#L168-L211)

### apfel.expr.affirm.AffirmPredicate.__call__

*method*

```python
def __call__(value: T) -> bool
```

Test if the value satisfies the predicate.
This function enforces returning a boolean value.

**Parameters**

- `value` (`T`) — The value to be tested.

**Returns**

- `bool` (`bool`) — Whether the value satisfies the predicate.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/expr/affirm.py#L186-L197)

### apfel.expr.affirm.AffirmPredicate.fail_message

*method* · *abstract*

```python
def fail_message(argument_expr: ast.expr | None, value: T) -> str
```

When the predicate fails, convert inputs to a formattable string explaining the reason.

**Parameters**

- `argument_expr` (`ast.expr | None`) — The AST expression of the argument passed to `affirm`, before evaluation. May be `None` if not available.
- `value` (`T`) — The actual value being affirmed.

**Returns**

- `str` (`str`) — A string explaining the reason for failure.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/expr/affirm.py#L199-L211)

### apfel.expr.affirm.AffirmPredicate.test

*method* · *abstract*

```python
def test(value: T) -> bool
```

Test if the value satisfies the predicate.

**Parameters**

- `value` (`T`) — The value to be tested.

**Returns**

- `bool` (`bool`) — Whether the value satisfies the predicate.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/expr/affirm.py#L173-L184)

## apfel.expr.affirm.is_type

*class*

```python
class is_type(AffirmPredicate)
```

Bases: `apfel.expr.affirm.AffirmPredicate`

Assert whether the value is exactly the specified type.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/expr/affirm.py#L241-L271)

### apfel.expr.affirm.is_type.ty

*attribute* · *class attribute* · *instance attribute*

```python
ty = object
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/expr/affirm.py#L246-L246)

### apfel.expr.affirm.is_type.__call__

*method*

```python
def __call__(value) -> bool
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/expr/affirm.py#L252-L254)

### apfel.expr.affirm.is_type.__class_getitem__

*method*

```python
def __class_getitem__(item)
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/expr/affirm.py#L263-L267)

### apfel.expr.affirm.is_type.fail_message

*method*

```python
def fail_message(argument_expr: ast.expr | None, value) -> str
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/expr/affirm.py#L269-L271)

### apfel.expr.affirm.is_type.test

*method*

```python
def test(value) -> bool
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/expr/affirm.py#L248-L250)

### apfel.expr.affirm.is_type.type

*method* · *cached* · *classmethod*

```python
def type(ty)
```

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/expr/affirm.py#L256-L261)

## apfel.expr.affirm.affirm

*function*

```python
def affirm(value: Any | T, predicate: type[is_type[U]] | type[type[T]] | AffirmPredicate[T] | Callable[[T], bool] | Callable[[T], Any] | bool | Any = None) -> U | T
```

Assert the value according to the predicate, return it if it is true.
This is the expression form of [:python `assert`](https://docs.python.org/3/reference/simple_stmts.html#the-assert-statement).

See [module-level documentation](affirm#affirm) for detailed usage.

**Parameters**

- `value` (`T`) — The value to be asserted.
- `predicate` (`Callable[[T], bool] | bool | None`) (default: `None`) — The predicate to be used for assertion. If None, evaluate the truthiness of the value.

**Returns**

- `T` (`U | T`) — The value asserted.

**Raises**

- `AssertionError` — If the value is not true.

[View source](https://github.com/Yixuan-Wang/apfel/blob/main/src/apfel/expr/affirm.py#L80-L165)
