Repository: great-expectations/great_expectations

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



Discussion:

Resolving patch:
diff --git a/great_expectations/dataset/base.py b/great_expectations/dataset/base.py
--- a/great_expectations/dataset/base.py
+++ b/great_expectations/dataset/base.py
@@ -327,7 +327,7 @@ def format_column_map_output(self,
 
         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 @@ def calc_map_expectation_success(self, success_count, nonnull_count, exception_c
                 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
--- a/great_expectations/dataset/pandas_dataset.py
+++ b/great_expectations/dataset/pandas_dataset.py
@@ -54,7 +54,7 @@ def inner_wrapper(self, column, mostly=None, output_format=None, *args, **kwargs
             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 @@ def inner_wrapper(self, column, output_format = None, *args, **kwargs):
             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 @@ def inner_wrapper(self, column, output_format = None, *args, **kwargs):
                 }
 
             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 @@ def expect_column_values_to_not_be_null(self, column, mostly=None, output_format
         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 @@ def expect_column_values_to_be_null(self, column, mostly=None, output_format=Non
         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
--- 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 @@ def test_set_default_expectation_argument(self):
             }
         )
 
+    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
--- a/tests/test_pandas_dataset.py
+++ b/tests/test_pandas_dataset.py
@@ -1206,6 +1206,19 @@ def test_expectation_decorator_summary_mode(self):
             }
         )
 
+        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({