Package: bulwark
Bulwark's DocumentationBulwark is a package for convenient property-based testing of pandas dataframes.Documentation:https://bulwark.readthedocs.io/en/latest/index.htmlThis project was heavily influenced by the no-longer-supportedEngardelibrary
by Tom Augspurger(thanks for the head start, Tom!),
which itself was modeled after
the R libraryassertr.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.Installationpipinstallbulwarkorcondainstall-cconda-forgebulwarkNote that the latest version of Bulwark will only be compatible with newer version of Python, Numpy, and Pandas. This is to encourage upgrades that themselves can help minimize bugs, allow Bulwark to take advantage of the latest language/library features, reduce the technical debt of maintaining Bulwark, and to be consistent with Numpy's community version support recommendation inNEP 29. See the table below for officially supported versions:BulwarkPythonNumpyPandas0.6.0>=3.6>=1.15>=0.23.0<=0.5.3>=3.5>=1.8>=0.16.2UsageBulwark 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:importbulwark.decoratorsasdc@dc.IsShape((-1,10))@dc.IsMonotonic(strict=True)@dc.HasNoNans()defcompute(df):# complex operations to determine result...returnresult_dfStill want to have more robust test files?
Bulwark's got you covered there, too, with importable functions.importbulwark.checksasckdf.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)defcompute(df):# complex operations to determine result...returnresult_dfWhat if the test I want isn't part of the library?
Use the built-inCustomCheckto use your own custom function!importbulwark.checksasckimportbulwark.decoratorsasdcimportnumpyasnpimportpandasaspddeflen_longer_than(df,l):iflen(df)<=l:raiseAssertionError("df is not as long as expected.")returndf@dc.CustomCheck(len_longer_than,10,enabled=False)defappend_a_df(df,df2):returndf.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 disabledWhat if I want to run a lot of tests and want to see all the errors at once?
You can use the built-inMultiCheck.
It will collect all of the errors
and either display a warning message of throw an exception based on thewarnflag.
You can even use custom functions with MultiCheck:deflen_longer_than(df,l):iflen(df)<=l:raiseAssertionError("df is not as long as expected.")returndf# `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)defappend_a_df(df,df2):returndf.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)Seeexamplesto see more advanced usage.ContributingBulwark 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 seecontributing.mdfor how to get started.Thank you to all our past contributors, especially these folks: