Fork me on GitHub

The Assert Statement

The most natural way to write test conditions in Python is the assert statement, but a downside to it is that it doesn’t let you know the values used in the conditional expression that failed. This makes debugging test failures more difficult as you can’t easily tell why the test failed, only that it did.

Attest includes a hook for the assert statement, the effect of which is that assert expressions can be analyzed and inspected. Using it is easy, just import it in the test modules you wish to use it in, and make sure Attest is imported before your tests (this is already the case in most setups):

from attest import assert_hook
assert str(2 + 2) == '5'

If used in a test, the above assertion would in Attest result in output including assert (str(4) == '5') which tells you the result of 2 + 2. This works also to expand the values of variables.

If you’re having issues with the assert hook on CPython 2.5, it is likely due to its inability to compile AST nodes to code objects. You can disable the hook conditionally by the presence of this capability easily:

from attest import AssertImportHook, COMPILES_AST
if not COMPILES_AST:
    AssertImportHook.disable()

By default, the hook is enabled when Attest is first imported. If Python can’t compile AST nodes and the hook is enabled, Attest tries to render the AST into source code for compilation, which works but loses the line numbers metadata in tracebacks.

assert_hook(expr, msg='', globals=None, locals=None)[source]

Like assert, but using ExpressionEvaluator. If you import this in test modules and the AssertImportHook is installed (which it is automatically the first time you import from attest), assert statements are rewritten as a call to this.

The import must be a top-level from import, example:

from attest import Tests, assert_hook

New in version 0.5.

class AssertImportHook[source]

An importer that transforms imported modules with AssertTransformer.

New in version 0.5.

classmethod disable()[source]

Disable the import hook.

classmethod enable()[source]

Enable the import hook.

enabled

Class property, True if the hook is enabled.

Low-Level Utilities

class ExpressionEvaluator(expr, globals, locals)[source]

Evaluates expr in the context of globals and locals, expanding the values of variables and the results of binary operations, but keeping comparison and boolean operators.

>>> var = 1 + 2
>>> value = ExpressionEvaluator('var == 5 - 3', globals(), locals())
>>> repr(value)
'(3 == 2)'
>>> bool(value)
False

New in version 0.5.

class AssertTransformer(source, filename='')[source]

Parses source with _ast and transforms assert statements into calls to assert_hook().

Warning

CPython 2.5 doesn’t compile AST nodes and when that fails this transformer will generate source code from the AST instead. While Attest’s own tests passes on CPython 2.5, there might be code that it currently would render back incorrectly, most likely resulting in a failure. Because Python’s syntax is simple, this isn’t very likely, but you might want to disable() the import hook if you test regularly on CPython 2.5.

It also messes up the line numbers so they don’t match the original source code, meaning tracebacks will point to the line numbers in the generated source and preview the code on that line in the original source. The improved error message with the import hook is often worth it however, and failures will still point to the right file and function.

New in version 0.5.

code[source]

The node compiled into a code object.

make_module(name, newpath=None)[source]

Compiles the transformed code into a module object which it also inserts in sys.modules.

Returns:The module object.
node[source]

The transformed AST node.

should_rewrite[source]

True if the source imports assert_hook().