Repository: great-expectations/great_expectations

Issue:
KeyError when updating to 0.5.0
When updating `ge` to 0.5.0 any of my `expect_column_values_to_not_be_null` checks fail with a `KeyError`:

```json
{
    "success": false,
    "exception_info": {
        "raised_exception": true,
        "exception_traceback": "Traceback (most recent call last):\n  File \"/.../miniconda3/lib/python3.7/site-packages/great_expectations/data_asset/base.py\", line 828, in validate\n    expectation['kwargs']['result_format'] = parse_result_format(expectation['kwargs']['result_format'])\nKeyError: 'result_format'\n",
        "exception_message": "'result_format'"
    },
    "expectation_config": {
        "expectation_type": "expect_column_values_to_not_be_null",
        "kwargs": {
            "column": "TestCol"
        }
    }
}
```

I believe this has to do with the changes made in https://github.com/great-expectations/great_expectations/commit/5573162997d98bd5de728f62a188a3c7eebd716d or https://github.com/great-expectations/great_expectations/commit/a90546a9571522060303bb511ee1540354ff3b9a. 


Discussion:
Here's a minimal reproduction:

```python
import great_expectations as ge
import pandas as pd
import json

# create the expectation
iris = ge.read_csv('https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv')
iris.expect_column_values_to_not_be_null(column='sepal_length')
iris.validate()
# success 
# {'results': [{'success': True,
#    'result': {'element_count': 150,
#     'missing_count': 0,
#     'missing_percent': 0.0,
#     'unexpected_count': 0,
#     'unexpected_percent': 0.0,
#     'partial_unexpected_list': []},
#    'exception_info': {'raised_exception': False,
#     'exception_message': None,
#     'exception_traceback': None},
#    'expectation_config': {'expectation_type': 'expect_column_values_to_not_be_null',
#     'kwargs': {'column': 'sepal_length',
#      'result_format': {'result_format': 'BASIC',
#       'partial_unexpected_count': 0}}}}],
#  'success': True,
#  'statistics': {'evaluated_expectations': 1,
#   'successful_expectations': 1,
#   'unsuccessful_expectations': 0,
#   'success_percent': 100.0}}

iris.save_expectations_config('/tmp/iris.json')

with open('/tmp/iris.json') as f:
    config = json.load(f)

iris_again = ge.read_csv('https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv',expectations_config=config)
iris_again.validate()
```
```
{'results': [{'success': False,
   'exception_info': {'raised_exception': True,
    'exception_traceback': 'Traceback (most recent call last):\n  File "/.../miniconda3/lib/python3.7/site-packages/great_expectations/data_asset/base.py", line 828, in validate\n    expectation[\'kwargs\'][\'result_format\'] = parse_result_format(expectation[\'kwargs\'][\'result_format\'])\nKeyError: \'result_format\'\n',
    'exception_message': "'result_format'"},
   'expectation_config': {'expectation_type': 'expect_column_values_to_not_be_null',
    'kwargs': {'column': 'sepal_length'}}}],
 'success': False,
 'statistics': {'evaluated_expectations': 1,
  'successful_expectations': 0,
  'unsuccessful_expectations': 1,
  'success_percent': 0.0}}
```




Thank you for flagging this; I'll look into it right away.
My best guess was that it was the removal of:

```python
if result_format is None:
      result_format = {}
```
in line 813 of https://github.com/great-expectations/great_expectations/commit/5573162997d98bd5de728f62a188a3c7eebd716d#diff-6d7e0a0c9d7105b4421072d12396e994L813

Resolving patch:
diff --git a/great_expectations/data_asset/base.py b/great_expectations/data_asset/base.py
--- a/great_expectations/data_asset/base.py
+++ b/great_expectations/data_asset/base.py
@@ -817,17 +817,6 @@ def validate(self, expectations_config=None, evaluation_parameters=None, catch_e
                 if result_format is not None:
                     expectation['kwargs'].update({'result_format': result_format})
 
-                # Counting the number of unexpected values can be expensive when there is a large
-                # number of np.nan values.
-                # This only happens on expect_column_values_to_not_be_null expectations.
-                # Since there is no reason to look for most common unexpected values in this case,
-                # we will instruct the result formatting method to skip this step.
-
-                if expectation['expectation_type'] in ['expect_column_values_to_not_be_null',
-                                                       'expect_column_values_to_be_null']:
-                    expectation['kwargs']['result_format'] = parse_result_format(expectation['kwargs']['result_format'])
-                    expectation['kwargs']['result_format']['partial_unexpected_count'] = 0
-
                 # A missing parameter should raise a KeyError
                 evaluation_args = self._build_evaluation_parameters(
                     expectation['kwargs'], evaluation_parameters)
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
@@ -69,7 +69,12 @@ def inner_wrapper(self, column, mostly=None, result_format=None, *args, **kwargs
             ignore_values = [None, np.nan]
             if func.__name__ in ['expect_column_values_to_not_be_null', 'expect_column_values_to_be_null']:
                 ignore_values = []
-                result_format['partial_unexpected_count'] = 0  # Optimization to avoid meaningless computation for these expectations
+                # Counting the number of unexpected values can be expensive when there is a large
+                # number of np.nan values.
+                # This only happens on expect_column_values_to_not_be_null expectations.
+                # Since there is no reason to look for most common unexpected values in this case,
+                # we will instruct the result formatting method to skip this step.
+                result_format['partial_unexpected_count'] = 0 
 
             series = self[column]
 
@@ -111,6 +116,7 @@ def inner_wrapper(self, column, mostly=None, result_format=None, *args, **kwargs
                 del return_obj['result']['unexpected_percent_nonmissing']
                 try:
                     del return_obj['result']['partial_unexpected_counts']
+                    del return_obj['result']['partial_unexpected_list']
                 except KeyError:
                     pass
 
diff --git a/great_expectations/dataset/sqlalchemy_dataset.py b/great_expectations/dataset/sqlalchemy_dataset.py
--- a/great_expectations/dataset/sqlalchemy_dataset.py
+++ b/great_expectations/dataset/sqlalchemy_dataset.py
@@ -60,7 +60,12 @@ def inner_wrapper(self, column, mostly=None, result_format=None, *args, **kwargs
             ignore_values = [None]
             if func.__name__ in ['expect_column_values_to_not_be_null', 'expect_column_values_to_be_null']:
                 ignore_values = []
-                result_format['partial_unexpected_count'] = 0  # Optimization to avoid meaningless computation for these expectations
+                # Counting the number of unexpected values can be expensive when there is a large
+                # number of np.nan values.
+                # This only happens on expect_column_values_to_not_be_null expectations.
+                # Since there is no reason to look for most common unexpected values in this case,
+                # we will instruct the result formatting method to skip this step.
+                result_format['partial_unexpected_count'] = 0 
 
             count_query = sa.select([
                 sa.func.count().label('element_count'),
@@ -149,6 +154,7 @@ def inner_wrapper(self, column, mostly=None, result_format=None, *args, **kwargs
                 del return_obj['result']['unexpected_percent_nonmissing']
                 try:
                     del return_obj['result']['partial_unexpected_counts']
+                    del return_obj['result']['partial_unexpected_list']
                 except KeyError:
                     pass
 


Test patch: