ensure is a set of simple assertion helpers that let you write more expressive, literate, concise, and readable
Pythonic code for validating conditions. It’s inspired by should.js,
expect.js, and builds on top of the
unittest/JUnit assert helpers.

If you use Python 3, you can use ensure to enforce your function signature annotations: see
PEP 3107 and the
@ensure_annotations decorator below.

Because ensure is fast, is a standalone library (not part of a test framework), doesn’t monkey-patch anything or use DSLs,
and doesn’t use the assert statement (which is liable to be turned off with the -O flag), it can be used to validate
conditions in production code, not just for testing (though it certainly works as a BDD test utility library).

Aside from better looking code, a big reason to use ensure is that it provides more consistent, readable, and
informative error messages when things go wrong. See
Motivation and Goals for more.

fromensureimportensureensure(1).is_an(int)ensure({1:{2:3}}).equals({1:{2:3}}).also.contains(1)ensure({1:"a"}).has_key(1).whose_value.has_length(1)ensure.each_of([{1:2},{3:4}]).is_a(dict).of(int).to(int)ensure(int).called_with("1100101",base=2).returns(101)ensure(dict).called_with(1,2).raises(TypeError)check(1).is_a(float).or_raise(Exception,"An error happened: {msg}. See http://example.com for more information.")

The ensure module exports the Ensure class and its convenience instance ensure. Instances of the class are
callable, and the call will reset the contents that the instance is inspecting, so you can reuse it for many checks (as
seen above).

The class raises EnsureError (a subclass of AssertionError) by default.

There are several ways to chain clauses, depending on the grammatical context: .also, .which, and
.whose_value are available per examples below.

You can pass a callable or exception class as the error_factory keyword argument to Ensure(), or you can use the
Check class or its convenience instance check(). This class behaves like Ensure, but does not raise errors
immediately. It saves them and chains the methods otherwise(), or_raise() and or_call() to the end of the
clauses.

fromensureimportcheckcheck("w00t").is_an(int).or_raise(Exception)check(1).is_a(float).or_raise(Exception,"An error happened: {msg}. See http://example.com for more information.")check("w00t").is_an(int).or_raise(MyException,1,2,x=3,y=4)

Many BDD assertion libraries suffer from an excess of magic, or end up having to construct statements that don’t parse
as English easily. ensure is deliberately kept simple to avoid succumbing to either issue. The
source is easy to read and extend.

Work remains to make error messages raised by ensure even more readable, informative, and consistent. Going forward,
ability to introspect exceptions to extract structured error information will be a major development
focus. You will be in control of how much information is presented in each error, which context it’s thrown from, and
what introspection capabilities the exception object will have.

The original use case for ensure is as an I/O validation helper for API endpoints, where the client needs to be sent a
very clear message about what went wrong, some structured information (such as an HTTP error code and machine-readable
reference to a failing element) may need to be added, and some information may need to be hidden from the client. To
further improve on that, we will work on better error translation, marshalling, message formatting, and schema
validation helpers.

error_factory – Class or callable (e.g. Exception) which will be invoked to produce the resulting exception.
You can define a custom callable here; it will be given the underlying predicate’s exception (AssertError)
as the first argument, followed by any arguments passed to or_raise.

message – String to be formatted and passed as the first argument to error_factory. If this is given, subsequent
arguments passed to or_raise will be used to format contents of the string, and will not be passed to
error_factory. The keyword argument error will be set to the underlying predicate’s exception.

error_factory – Class or callable (e.g. Exception) which will be invoked to produce the resulting exception.
You can define a custom callable here; it will be given the underlying predicate’s exception (AssertError)
as the first argument, followed by any arguments passed to or_raise.

message – String to be formatted and passed as the first argument to error_factory. If this is given, subsequent
arguments passed to or_raise will be used to format contents of the string, and will not be passed to
error_factory. The keyword argument error will be set to the underlying predicate’s exception.

Constructs a root-level inspector, which can perform a variety of checks (predicates) on subjects passed to
it. If the checks do not pass, by default EnsureError is raised. This can be configured by passing the
error_factory keyword to the constructor.

Subjects can be passed to the inspector at construction time or by calling the resulting object (each call resets
the subject):

Ensure(1).is_an(int)e=Ensure()e(1).is_an(int)

Some predicates return child inspectors which can be chained into a series of predicates, for example:

Decorator to be used on functions with annotations. Runs type checks to enforce annotations. Raises
EnsureError if any argument passed to f is not of the type specified by the annotation. Also raises
EnsureError if the return value of f is not of the type specified by the annotation. Examples:

Decorator to be used on functions with annotations. Runs type checks to enforce annotations. Raises
EnsureError if any argument passed to f is not of the type specified by the annotation. Also raises
EnsureError if the return value of f is not of the type specified by the annotation. Examples: