Repository: great-expectations/great_expectations

Issue:
Can't pass both a connection string and config options to `connect` method in sqlalchemycontext
In theory, the `options` argument in the `connect` method is meant to allow you to pass arguments to the connection method for either the pandas or sql context. However, for the sqlalchemy context, the first argument to `create_engine` is an unnamed argument containing the database URL. I can't find a way to pass both a db connection string and a dict of config options, which means that I can't use the class connect to databases where I require non-default options. My current workaround is to create my own engine and pass it in to `SqlAlchemyDataset`.

The current data context test demonstrates this behavior by passing a connection string rather than config options to the `connect` method: https://github.com/great-expectations/great_expectations/blob/d7a4ee03cfce8bea66c5f91573bb87e4385b1eb1/tests/test_data_contexts/test_data_contexts.py#L40


Discussion:

Resolving patch:
diff --git a/great_expectations/data_context/__init__.py b/great_expectations/data_context/__init__.py
--- a/great_expectations/data_context/__init__.py
+++ b/great_expectations/data_context/__init__.py
@@ -1,7 +1,7 @@
 from .pandas_context import PandasCSVDataContext
 from .sqlalchemy_context import SqlAlchemyDataContext
 
-def get_data_context(context_type, options):
+def get_data_context(context_type, options, *args, **kwargs):
     """Return a data_context object which exposes options to list datasets and get a dataset from
     that context. This is a new API in Great Expectations 0.4, and is subject to rapid change.
 
@@ -10,8 +10,8 @@ def get_data_context(context_type, options):
     :return: a new DataContext object
     """
     if context_type == "SqlAlchemy":
-        return SqlAlchemyDataContext(options)
+        return SqlAlchemyDataContext(options, *args, **kwargs)
     elif context_type == "PandasCSV":
-        return PandasCSVDataContext(options)
+        return PandasCSVDataContext(options, *args, **kwargs)
     else:
-        raise ValueError("Unknown data context.")
\ No newline at end of file
+        raise ValueError("Unknown data context.")
diff --git a/great_expectations/data_context/base.py b/great_expectations/data_context/base.py
--- a/great_expectations/data_context/base.py
+++ b/great_expectations/data_context/base.py
@@ -4,8 +4,8 @@ class DataContext(object):
 
     Warning: this feature is new in v0.4 and may change based on community feedback.
     """
-    def __init__(self, options):
-        self.connect(options)
+    def __init__(self, options, *args, **kwargs):
+        self.connect(options, *args, **kwargs)
 
     def connect(self, options):
         return NotImplementedError
diff --git a/great_expectations/data_context/sqlalchemy_context.py b/great_expectations/data_context/sqlalchemy_context.py
--- a/great_expectations/data_context/sqlalchemy_context.py
+++ b/great_expectations/data_context/sqlalchemy_context.py
@@ -16,8 +16,8 @@ def __init__(self, *args, **kwargs):
         super(SqlAlchemyDataContext, self).__init__(*args, **kwargs)
         self.meta = MetaData()
 
-    def connect(self, options):
-        self.engine = create_engine(options)
+    def connect(self, options, *args, **kwargs):
+        self.engine = create_engine(options, *args, **kwargs)
 
     def list_datasets(self):
         self.meta.reflect(bind=self.engine)


Test patch:
diff --git a/tests/test_data_contexts/test_data_contexts.py b/tests/test_data_contexts/test_data_contexts.py
--- a/tests/test_data_contexts/test_data_contexts.py
+++ b/tests/test_data_contexts/test_data_contexts.py
@@ -37,7 +37,7 @@ def test_invalid_data_context():
 
 
 def test_sqlalchemy_data_context(test_db_connection_string):
-    context = get_data_context('SqlAlchemy', test_db_connection_string)
+    context = get_data_context('SqlAlchemy', test_db_connection_string, echo=False)
 
     assert context.list_datasets() == ['table_1', 'table_2']
     dataset = context.get_dataset('table_1')
diff --git a/tests/test_dataset.py b/tests/test_dataset.py
--- a/tests/test_dataset.py
+++ b/tests/test_dataset.py
@@ -1139,9 +1139,9 @@ def test_test_column_aggregate_expectation_function(self):
         })
         def expect_second_value_to_be(self, column, value, result_format=None, include_config=False, catch_exceptions=None, meta=None):
             return {
-                "success": column.ix[1] == value,
+                "success": column.iloc[1] == value,
                 "result": {
-                    "observed_value": column.ix[1],
+                    "observed_value": column.iloc[1],
                 }
             }