Repository: great-expectations/great_expectations

Issue:
Add unit tests for `format_column_map_output` and `calc_map_expectation_success`

Discussion:

Patch:
diff --git a/.gitignore b/.gitignore
index 8cc0d85e1..7b686a190 100644
--- a/.gitignore
+++ b/.gitignore
@@ -103,3 +103,5 @@ ENV/
 
 # vim backup files
 *~
+
+.DS_Store
\ No newline at end of file
diff --git a/examples/notebooks/Distributional_Expectations_Demo.ipynb b/examples/notebooks/Distributional_Expectations_Demo.ipynb
index b6c61bd5d..4745ffa67 100644
--- a/examples/notebooks/Distributional_Expectations_Demo.ipynb
+++ b/examples/notebooks/Distributional_Expectations_Demo.ipynb
@@ -2,7 +2,7 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -14,7 +14,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -29,7 +29,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -57,7 +57,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -69,7 +69,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -78,7 +78,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -87,7 +87,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -104,7 +104,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -115,7 +115,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -127,7 +127,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -138,7 +138,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -150,7 +150,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -161,7 +161,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -172,7 +172,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -184,7 +184,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -195,7 +195,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -206,7 +206,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -217,7 +217,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -229,7 +229,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -241,7 +241,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -252,7 +252,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -263,7 +263,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -275,7 +275,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -286,7 +286,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -298,7 +298,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -309,7 +309,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -321,7 +321,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -336,7 +336,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -351,7 +351,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -362,7 +362,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -374,7 +374,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -402,7 +402,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -413,7 +413,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -424,7 +424,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -435,7 +435,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -446,7 +446,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -457,7 +457,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -468,7 +468,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -479,7 +479,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -491,7 +491,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -502,7 +502,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -513,7 +513,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -524,7 +524,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -539,7 +539,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -550,7 +550,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -561,7 +561,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -573,7 +573,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -584,7 +584,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true,
     "scrolled": true
@@ -596,7 +596,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -611,7 +611,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -622,7 +622,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -638,7 +638,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -650,7 +650,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -681,4 +681,4 @@
  },
  "nbformat": 4,
  "nbformat_minor": 2
-}
+}
\ No newline at end of file
diff --git a/examples/notebooks/Distributional_Expectations_Demo_Prep.ipynb b/examples/notebooks/Distributional_Expectations_Demo_Prep.ipynb
index b00d6ef62..4e62e3846 100644
--- a/examples/notebooks/Distributional_Expectations_Demo_Prep.ipynb
+++ b/examples/notebooks/Distributional_Expectations_Demo_Prep.ipynb
@@ -2,7 +2,7 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -14,7 +14,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -43,7 +43,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -60,7 +60,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {
     "collapsed": true
    },
@@ -80,7 +80,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -96,7 +96,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 0,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -130,4 +130,4 @@
  },
  "nbformat": 4,
  "nbformat_minor": 2
-}
+}
\ No newline at end of file
diff --git a/great_expectations/dataset/base.py b/great_expectations/dataset/base.py
index 72e23313b..14acf8ecf 100644
--- a/great_expectations/dataset/base.py
+++ b/great_expectations/dataset/base.py
@@ -327,7 +327,7 @@ class DataSet(object):
 
         return return_obj
 
-    def calc_map_expectation_success(self, success_count, nonnull_count, exception_count, mostly):
+    def calc_map_expectation_success(self, success_count, nonnull_count, mostly):
         if nonnull_count > 0:
             percent_success = float(success_count)/nonnull_count
 
@@ -335,7 +335,7 @@ class DataSet(object):
                 success = bool(percent_success >= mostly)
 
             else:
-                success = bool(exception_count == 0)
+                success = bool(nonnull_count-success_count == 0)
 
         else:
             success = True
diff --git a/great_expectations/dataset/pandas_dataset.py b/great_expectations/dataset/pandas_dataset.py
index 3e3f68fa4..dd8fba971 100644
--- a/great_expectations/dataset/pandas_dataset.py
+++ b/great_expectations/dataset/pandas_dataset.py
@@ -54,7 +54,7 @@ class MetaPandasDataSet(DataSet):
             exception_index_list = list(series[(boolean_mapped_success_values==False)&(boolean_mapped_null_values==False)].index)
             exception_count = len(exception_list)
 
-            success, percent_success = self.calc_map_expectation_success(success_count, nonnull_count, exception_count, mostly)
+            success, percent_success = self.calc_map_expectation_success(success_count, nonnull_count, mostly)
 
             return_obj = self.format_column_map_output(
                 output_format, success,
@@ -93,9 +93,10 @@ class MetaPandasDataSet(DataSet):
             series = self[column]
             null_indexes = series.isnull()
 
+            element_count = int(len(series))
             nonnull_values = series[null_indexes == False]
             nonnull_count = (null_indexes == False).sum()
-            null_count = nonnull_count - len(series)
+            null_count = element_count - nonnull_count
 
             result_obj = func(self, nonnull_values, *args, **kwargs)
 
@@ -112,18 +113,17 @@ class MetaPandasDataSet(DataSet):
                 }
 
             elif (output_format == "SUMMARY"):
+                new_summary_obj = {
+                    "element_count": element_count,
+                    "missing_count": null_count,
+                    "missing_percent": null_count*1.0 / element_count if element_count > 0 else None
+                }
+
                 if "summary_obj" in result_obj and result_obj["summary_obj"] is not None:
-                    result_obj["summary_obj"].update({
-                        "element_count": nonnull_count,
-                        "missing_count": null_count,
-                        "missing_percent": nonnull_count / null_count if null_count > 0 else 0
-                    })
+                    result_obj["summary_obj"].update(new_summary_obj)
                 else:
-                    result_obj["summary_obj"] = {
-                        "element_count": nonnull_count,
-                        "missing_count": null_count,
-                        "missing_percent": nonnull_count / null_count if null_count > 0 else 0
-                    }
+                    result_obj["summary_obj"] = new_summary_obj
+
                 return_obj = {
                     "success" : bool(result_obj["success"]),
                     "true_value" : result_obj["true_value"],
@@ -238,7 +238,7 @@ class PandasDataSet(MetaPandasDataSet, pd.DataFrame):
         exception_count = len(exception_list)
 
         # Pass element_count instead of nonnull_count, because that's the right denominator for this expectation
-        success, percent_success = self.calc_map_expectation_success(success_count, element_count, exception_count, mostly)
+        success, percent_success = self.calc_map_expectation_success(success_count, element_count, mostly)
 
         return_obj = self.format_column_map_output(
             output_format, success,
@@ -271,7 +271,7 @@ class PandasDataSet(MetaPandasDataSet, pd.DataFrame):
         exception_count = len(exception_list)
 
         # Pass element_count instead of nonnull_count, because that's the right denominator for this expectation
-        success, percent_success = self.calc_map_expectation_success(success_count, element_count, exception_count, mostly)
+        success, percent_success = self.calc_map_expectation_success(success_count, element_count, mostly)
 
         return_obj = self.format_column_map_output(
             output_format, success,


Test patch:
diff --git a/tests/test_dataset.py b/tests/test_dataset.py
index c71006652..50e96e1ef 100644
--- a/tests/test_dataset.py
+++ b/tests/test_dataset.py
@@ -1,3 +1,4 @@
+import pandas as pd
 import great_expectations as ge
 
 import unittest
@@ -80,5 +81,153 @@ class TestDataset(unittest.TestCase):
             }
         )
 
+    def test_format_column_map_output(self):
+        df = ge.dataset.PandasDataSet({
+            "x" : list("abcdefghijklmnopqrstuvwxyz")
+        })
+
+        success = True
+        element_count = 20
+        nonnull_values = pd.Series(range(15))
+        nonnull_count = 15
+        boolean_mapped_success_values = pd.Series([True for i in range(15)])
+        success_count = 15
+        exception_list = []
+        exception_index_list = []
+
+        self.assertEqual(
+            df.format_column_map_output(
+                "BOOLEAN_ONLY",
+                success,
+                element_count,
+                nonnull_values, nonnull_count,
+                boolean_mapped_success_values, success_count,
+                exception_list, exception_index_list
+            ),
+            True
+        )
+
+        self.assertEqual(
+            df.format_column_map_output(
+                "BASIC",
+                success,
+                element_count,
+                nonnull_values, nonnull_count,
+                boolean_mapped_success_values, success_count,
+                exception_list, exception_index_list
+            ),
+            {
+                'success': True,
+                'summary_obj': {
+                    'exception_percent': 0.0,
+                    'partial_exception_list': [],
+                    'exception_percent_nonmissing': 0.0,
+                    'exception_count': 0
+                }
+            }
+        )
+
+        self.assertEqual(
+            df.format_column_map_output(
+                "COMPLETE",
+                success,
+                element_count,
+                nonnull_values, nonnull_count,
+                boolean_mapped_success_values, success_count,
+                exception_list, exception_index_list
+            ),
+            {
+                'success': True,
+                'exception_list': [],
+                'exception_index_list': [],
+            }
+        )
+
+        self.assertEqual(
+            df.format_column_map_output(
+                "SUMMARY",
+                success,
+                element_count,
+                nonnull_values, nonnull_count,
+                boolean_mapped_success_values, success_count,
+                exception_list, exception_index_list
+            ),
+            {
+                'success': True,
+                'summary_obj': {
+                    'element_count': 20,
+                    'exception_count': 0,
+                    'exception_percent': 0.0,
+                    'exception_percent_nonmissing': 0.0,
+                    'missing_count': 5,
+                    'missing_percent': 0.25,
+                    'partial_exception_counts': {},
+                    'partial_exception_index_list': [],
+                    'partial_exception_list': []
+                }
+            }
+        )
+
+
+
+    def test_calc_map_expectation_success(self):
+        df = ge.dataset.PandasDataSet({
+            "x" : list("abcdefghijklmnopqrstuvwxyz")
+        })
+        self.assertEqual(
+            df.calc_map_expectation_success(
+                success_count=10,
+                nonnull_count=10,
+                mostly=None
+            ),
+            (True, 1.0)
+        )
+
+        self.assertEqual(
+            df.calc_map_expectation_success(
+                success_count=90,
+                nonnull_count=100,
+                mostly=.9
+            ),
+            (True, .9)
+        )
+
+        self.assertEqual(
+            df.calc_map_expectation_success(
+                success_count=90,
+                nonnull_count=100,
+                mostly=.8
+            ),
+            (True, .9)
+        )
+
+        self.assertEqual(
+            df.calc_map_expectation_success(
+                success_count=80,
+                nonnull_count=100,
+                mostly=.9
+            ),
+            (False, .8)
+        )
+
+        self.assertEqual(
+            df.calc_map_expectation_success(
+                success_count=0,
+                nonnull_count=0,
+                mostly=None
+            ),
+            (True, None)
+        )
+
+        self.assertEqual(
+            df.calc_map_expectation_success(
+                success_count=0,
+                nonnull_count=100,
+                mostly=None
+            ),
+            (False, 0.0)
+        )
+
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/tests/test_pandas_dataset.py b/tests/test_pandas_dataset.py
index 7490d5102..2f92e50e2 100644
--- a/tests/test_pandas_dataset.py
+++ b/tests/test_pandas_dataset.py
@@ -1206,6 +1206,19 @@ class TestPandasDataset(unittest.TestCase):
             }
         )
 
+        self.assertEqual(
+            df.expect_column_mean_to_be_between("x", 3, 7, output_format="SUMMARY"),
+            {
+                'success': True,
+                'true_value': 4.375,
+                'summary_obj': {
+                    'element_count': 10,
+                    'missing_count': 2,
+                    'missing_percent': .2
+                },
+            }
+        )
+
     def test_positional_arguments(self):
 
         df = ge.dataset.PandasDataSet({