Literate BDD assertions in Python with no magic
Project description
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.
Because ensure 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.
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.
Installation
pip install ensure
Synopsis
from ensure import ensure
ensure({1: {2: 3}}).equals({1: {2: 3}})
ensure({1: {2: 3}}).is_not_equal_to({1: {2: 4}})
ensure(True).does_not_equal(False)
ensure(1).is_an(int)
ensure(1).is_in(range(10))
ensure(True).is_a(bool)
ensure(True).is_(True)
ensure(True).is_not(False)
ensure(range(8)).contains(5)
ensure(["spam"]).contains_none_of(["eggs", "ham"])
ensure(["train", "boat"]).contains_one_of(["train"])
ensure("abcdef").contains_some_of("abcxyz")
ensure("abcdef").contains_one_or_more_of("abcxyz")
ensure("abcdef").contains_all_of("acf")
ensure("abcd").contains_only("dcba")
ensure("abc").does_not_contain("xyz")
ensure([1, 2, 3]).contains_no(float)
ensure(1).is_in(range(10))
ensure("z").is_not_in("abc")
ensure(None).is_not_in([])
ensure(dict).has_attribute('__contains__').which.is_callable()
ensure({1: "a"}).has_key(1).whose_value.has_length(1)
ensure(1).is_true()
ensure(0).is_false()
ensure(None).is_none()
ensure(1).is_not_none()
ensure("").is_empty()
ensure([1, 2]).is_nonempty()
ensure(1.1).is_a(float)
ensure(KeyError()).is_an(Exception)
ensure({x: str(x) for x in range(5)}).is_a_nonempty(dict).of(int).to(str)
ensure({}).is_an_empty(dict)
ensure(None).is_not_a(list)
import re
ensure("abc").matches("A", flags=re.IGNORECASE)
ensure([1, 2, 3]).is_an_iterable_of(int)
ensure([1, 2, 3]).is_a_list_of(int)
ensure({1, 2, 3}).is_a_set_of(int)
ensure({1: 2, 3: 4}).is_a_mapping_of(int).to(int)
ensure({1: 2, 3: 4}).is_a_dict_of(int).to(int)
ensure({1: 2, 3: 4}).is_a(dict).of(int).to(int)
ensure(10**100).is_numeric()
ensure(lambda: 1).is_callable()
ensure("abc").has_length(3)
ensure(1).is_greater_than(0)
ensure(0).is_less_than(1)
ensure(1).is_greater_than_or_equal_to(1)
ensure(0).is_less_than_or_equal_to(0)
ensure(1).is_positive()
ensure(1.1).is_a_positive(float)
ensure(-1).is_negative()
ensure(-1).is_a_negative(int)
ensure(0).is_nonnegative()
ensure(0).is_a_nonnegative(int)
ensure("{x} {y}".format).called_with(x=1, y=2).equals("1 2")
ensure("{x} {y}".format).with_args(x=1, y=2).is_a(str)
ensure(dict).called_with(1, 2).raises(TypeError)
with ensure().raises(ZeroDivisionError):
1/0
with ensure().raises_regex(NameError, "'w00t' is not defined"):
w00t
Raising custom exceptions
from ensure import Ensure
class MyException(Exception):
def __init__(self, e):
pass
ensure = Ensure(error_factory=MyException)
ensure("w00t").is_an(int)
def build_fancy_exception(original_exception):
return MyException(original_exception)
ensure = Ensure(error_factory=build_fancy_exception)
ensure("w00t").is_an(int)
Motivation and goals
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.
Links
Bugs
Please report bugs, issues, feature requests, etc. on GitHub.
License
Licensed under the terms of the Apache License, Version 2.0.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file ensure-0.0.6.tar.gz
.
File metadata
- Download URL: ensure-0.0.6.tar.gz
- Upload date:
- Size: 6.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | a812cc8b6c7bb8a8b4f1a57c77dc1d67ed7f53ecfc47d437a16e94442cb7025e |
|
MD5 | 6addeceb862255b5514f0d9d8bd68ba5 |
|
BLAKE2b-256 | 381b60a8a0f9540632f46a2fe0379e3cd5720d941aa424a13fb3f1cc10486036 |