Skip to content
Bulwark is a package for convenient property-based testing of pandas dataframes, supported for Python 3.5+.
Python
Branch: master
Clone or download
Latest commit a26eb3d Nov 14, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github Create FUNDING.yml Nov 14, 2019
bulwark Hotfix enabled and CustomCheck otherwise not working; swap `custom_ch… Nov 11, 2019
docs Fix trailing whitespace Oct 22, 2019
tests Hotfix enabled and CustomCheck otherwise not working; swap `custom_ch… Nov 11, 2019
.codecov.yaml
.coveragerc Add .coveragerc, pytest-cov, codecov, .codecov.yaml; rename readthedo… Aug 24, 2019
.flake8 Cleanup length Aug 24, 2019
.gitignore Added venv folder to gitignore Jul 28, 2019
.isort.cfg Add precommit w/ autopep8, isort; add tox; update travis to use tox-t… Aug 24, 2019
.pre-commit-config.yaml Add precommit w/ autopep8, isort; add tox; update travis to use tox-t… Aug 24, 2019
.readthedocs.yml
.travis.yml Add .coveragerc, pytest-cov, codecov, .codecov.yaml; rename readthedo… Aug 24, 2019
CHANGELOG.md Hotfix enabled and CustomCheck otherwise not working; swap `custom_ch… Nov 11, 2019
LICENSE Add license Jan 12, 2019
MANIFEST.in Hotfix missing project_info.py in MANIFEST.in Jul 27, 2019
README.md Hotfix enabled and CustomCheck otherwise not working; swap `custom_ch… Nov 11, 2019
requirements.txt Remove six Aug 19, 2019
setup.cfg Initial commit Jan 12, 2019
setup.py Add python_requires in setup.py Oct 22, 2019
tox.ini hotfix tox coverage-report Aug 24, 2019

README.md

Bulwark's Documentation

downloads

latest release supported python versions package status conda license

travis build status docs build status coverage status

Bulwark is a package for convenient property-based testing of pandas dataframes, supported for Python 3.5+.

Documentation: https://bulwark.readthedocs.io/en/latest/index.html

This project was heavily influenced by the no-longer-supported Engarde library by Tom Augspurger(thanks for the head start, Tom!), which itself was modeled after the R library assertr.

Why?

Data are messy, and pandas is one of the go-to libraries for analyzing tabular data. In the real world, data analysts and scientists often feel like they don't have the time or energy to think of and write tests for their data. Bulwark's goal is to let you check that your data meets your assumptions of what it should look like at any (and every) step in your code, without making you work too hard.

Installation

pip install bulwark

or

conda install -c conda-forge bulwark

Usage

Bulwark comes with checks for many of the common assumptions you might want to validate for the functions that make up your ETL pipeline, and lets you toss those checks as decorators on the functions you're already writing:

    import bulwark.decorators as dc

    @dc.IsShape((-1, 10))
    @dc.IsMonotonic(strict=True)
    @dc.HasNoNans()
    def compute(df):
        # complex operations to determine result
        ...
    return result_df

Still want to have more robust test files? Bulwark's got you covered there, too, with importable functions.

    import bulwark.checks as ck

    df.pipe(ck.has_no_nans())

Won't I have to go clean up all those decorators when I'm ready to go to production? Nope - just toggle the built-in "enabled" flag available for every decorator.

    @dc.IsShape((3, 2), enabled=False)
    def compute(df):
        # complex operations to determine result
        ...
    return result_df

What if the test I want isn't part of the library? Use the built-in CustomCheck to use your own custom function!

    import bulwark.checks as ck
    import bulwark.decorators as dc
    import numpy as np
    import pandas as pd

    def len_longer_than(df, l):
        if len(df) <= l:
            raise AssertionError("df is not as long as expected.")
        return df

    @dc.CustomCheck(len_longer_than, 10, enabled=False)
    def append_a_df(df, df2):
        return df.append(df2, ignore_index=True)

    df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
    df2 = pd.DataFrame({"a": [1, np.nan, 3, 4], "b": [4, 5, 6, 7]})

    append_a_df(df, df2)  # doesn't fail because the check is disabled

What if I want to run a lot of tests and want to see all the errors at once? You can use the built-in MultiCheck. It will collect all of the errors and either display a warning message of throw an exception based on the warn flag. You can even use custom functions with MultiCheck:

    def len_longer_than(df, l):
        if len(df) <= l:
            raise AssertionError("df is not as long as expected.")
        return df

    # `checks` takes a dict of function: dict of params for that function.
    # Note that those function params EXCLUDE df.
    # Also note that when you use MultiCheck, there's no need to use CustomCheck - just feed in the function.
    @dc.MultiCheck(checks={ck.has_no_nans: {"columns": None},
                           len_longer_than: {"l": 6}},
                   warn=False)
    def append_a_df(df, df2):
        return df.append(df2, ignore_index=True)

    df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
    df2 = pd.DataFrame({"a": [1, np.nan, 3, 4], "b": [4, 5, 6, 7]})

    append_a_df(df, df2)

See examples to see more advanced usage.

Contributing

Bulwark is always looking for new contributors! We work hard to make contributing as easy as possible, and previous open source experience is not required! Please see contributing.md for how to get started.

Thank you to all our past contributors, especially these folks:

You can’t perform that action at this time.