# i2.errors

Error objects

### Functions

| [`log_and_return`](#i2.errors.log_and_return)(msg[, logger])   | Pass `msg` to `logger` (`print` by default) and return it.   |
|----------------------------------------------------------------------------------|--------------------------------------------------------------|

### Classes

| [`HandleExceptions`](#i2.errors.HandleExceptions)([on_error])   | A context manager that catches and (specifically) handles specific exceptions.   |
|---------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
| [`ModuleNotFoundIgnore`](#i2.errors.ModuleNotFoundIgnore)()         | Context manager meant to ignore import errors.                                   |

### Exceptions

| [`AuthorizationError`](#i2.errors.AuthorizationError)                             | Base class for errors about what the caller is allowed to do.                |
|-------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------|
| [`DataError`](#i2.errors.DataError)                                      | Base class for errors about the data itself.                                 |
| [`DuplicateRecordError`](#i2.errors.DuplicateRecordError)                           | A `DataError` for a record that already exists.                              |
| [`ForbiddenError`](#i2.errors.ForbiddenError)                                 | An `AuthorizationError` for an operation that is not allowed.                |
| [`InputError`](#i2.errors.InputError)                                     | Raised for invalid input.                                                    |
| [`InterruptWithBlock`](#i2.errors.InterruptWithBlock)                             | Raise inside a `with` block to leave it early; pair with `HandleExceptions`. |
| [`NotFoundError`](#i2.errors.NotFoundError)                                  | A `DataError` for a record that does not exist.                              |
| [`OverwritesNotAllowed`](#i2.errors.OverwritesNotAllowed)(\*args[, forbidden_keys]) | To raise when writes are only allowed if the item doesn't already exist      |

### *exception* i2.errors.AuthorizationError

Bases: [`Exception`](https://docs.python.org/3/builtins/exceptions.html#Exception)

Base class for errors about what the caller is allowed to do.

### *exception* i2.errors.DataError

Bases: [`Exception`](https://docs.python.org/3/builtins/exceptions.html#Exception)

Base class for errors about the data itself.

### *exception* i2.errors.DuplicateRecordError

Bases: [`DataError`](#i2.errors.DataError)

A `DataError` for a record that already exists.

### *exception* i2.errors.ForbiddenError

Bases: [`AuthorizationError`](#i2.errors.AuthorizationError)

An `AuthorizationError` for an operation that is not allowed.

### *class* i2.errors.HandleExceptions(on_error=<factory>)

Bases: [`AbstractContextManager`](https://docs.python.org/3/library/contextlib.html#contextlib.AbstractContextManager)

A context manager that catches and (specifically) handles specific exceptions.

It takes one argument: A dict (or mapping) of exception type keys and callback
values. If within a with block, the particular (listed) exception happens,
the callback is called and it’s returned value is assigned to the
`HandleExceptions` instance’s `.exit_value` attribute.
That attribute will only exist if the with block existed with an exception
caught by `HandleExceptions`.

A callback is an argument-less function. If you need to specify arguments, you can
envoke the command pattern, using `functools.partial` to make a argument-less
function. See in the example below how we ask `HandleExceptions` to print a
specific string if a `ZeroDivisionError` happens:

```pycon
>>> from functools import partial
>>> def print_and_return(msg):
...     print(msg)
...     return msg
>>> with HandleExceptions({
...     ZeroDivisionError: partial(print_and_return, "You interrupted me"),
...     KeyboardInterrupt: lambda: 'imagine this is code to notify someone'
... }) as he:
...     print('This works')
...     0 / 0
...
This works
You interrupted me
```

You can check if the context exited with a handled exception, and if so, what
the callback returned value was.

```pycon
>>> he.exited_with_handled_exception()
True
>>> he.exit_value
'You interrupted me'
```

Also available, whether the exception was a handled one or not: The exception
instance itself:

```pycon
>>> he.exited_with_exception
ZeroDivisionError('division by zero')
```

If all you want to do though is print a string (and have the same string
available in the `exit_value` attribute, we got you covered!
Just specify a string and we’ll make that printer callaback for you!

```pycon
>>> from functools import partial
>>>
>>> with HandleExceptions({ZeroDivisionError: "You interrupted me again!"}):
...     print('This also works')
...     0 / 0
This also works
You interrupted me again!
```

Note that specifying `partial(print, "some message")` will work as a
“printing callback”, but the string won’t be available in `.exit_value` since
`print` returns None.

A few recipes now…

You can also use your own custom exception types to do things like interrupt
a with block early given some condition(s).

```pycon
>>> with HandleExceptions(
...     {InterruptWithBlock: "The with block was interrupted early."}
... ):
...     print('before condition')
...     x = 5 % 2
...     if x:
...         raise InterruptWithBlock()
...     print('after condition')
...
...
before condition
The with block was interrupted early.
```

#### TIP
If you need to do stuff with an exception, but reraise it, you can
still do that in your callback. Just say `raise` at the end of the callback!

```pycon
>>> def print_and_raise(msg):
...     print(msg)
...     raise
>>>
>>> with HandleExceptions({
...     ZeroDivisionError: partial(print_and_raise, "That again!"),
... }):
...     print('This also works')
...     0 / 0
This also works
That again!
Traceback (most recent call last):
    ...
ZeroDivisionError: division by zero
```

#### exited_with_handled_exception()

Whether the last `with` block ended on an exception listed in `on_error`.

#### initialize()

Forget the outcome of a previous `with` block (done on every `__enter__`).

### *exception* i2.errors.InputError

Bases: [`Exception`](https://docs.python.org/3/builtins/exceptions.html#Exception)

Raised for invalid input.

### *exception* i2.errors.InterruptWithBlock

Bases: [`BaseException`](https://docs.python.org/3/builtins/exceptions.html#BaseException)

Raise inside a `with` block to leave it early; pair with `HandleExceptions`.

```pycon
>>> with HandleExceptions({InterruptWithBlock: "stopped early"}) as h:
...     raise InterruptWithBlock()
...     print("never printed")
stopped early
>>> h.exit_value
'stopped early'
```

### *class* i2.errors.ModuleNotFoundIgnore

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Context manager meant to ignore import errors.
The use case in mind is when we want to condition some code on the existence of some package.

### *exception* i2.errors.NotFoundError

Bases: [`DataError`](#i2.errors.DataError)

A `DataError` for a record that does not exist.

### *exception* i2.errors.OverwritesNotAllowed(\*args, forbidden_keys=None, \*\*kwargs)

Bases: [`AuthorizationError`](#i2.errors.AuthorizationError)

To raise when writes are only allowed if the item doesn’t already exist

### i2.errors.log_and_return(msg, logger=<built-in function print>)

Pass `msg` to `logger` (`print` by default) and return it.
