Repository: great-expectations/great_expectations

Issue:
Use cleaner solution for non-truncating division in python 2
Prefer `from __future__ import division` to `1.*x/y`


Discussion:
Done inline during improve_partitions push.

Resolving patch:
diff --git a/great_expectations/execution_engine/sqlalchemy_execution_engine.py b/great_expectations/execution_engine/sqlalchemy_execution_engine.py
--- a/great_expectations/execution_engine/sqlalchemy_execution_engine.py
+++ b/great_expectations/execution_engine/sqlalchemy_execution_engine.py
@@ -36,6 +36,7 @@
 from great_expectations.expectations.row_conditions import parse_condition_to_sqlalchemy
 from great_expectations.util import (
     filter_properties_dict,
+    get_sqlalchemy_selectable,
     get_sqlalchemy_url,
     import_library_module,
 )
@@ -483,9 +484,9 @@ def get_domain_records(
 
             ignore_row_if = domain_kwargs["ignore_row_if"]
             if ignore_row_if == "both_values_are_missing":
-                selectable = (
+                selectable = get_sqlalchemy_selectable(
                     sa.select([sa.text("*")])
-                    .select_from(selectable)
+                    .select_from(get_sqlalchemy_selectable(selectable))
                     .where(
                         sa.not_(
                             sa.and_(
@@ -496,9 +497,9 @@ def get_domain_records(
                     )
                 )
             elif ignore_row_if == "either_value_is_missing":
-                selectable = (
+                selectable = get_sqlalchemy_selectable(
                     sa.select([sa.text("*")])
-                    .select_from(selectable)
+                    .select_from(get_sqlalchemy_selectable(selectable))
                     .where(
                         sa.not_(
                             sa.or_(
@@ -536,9 +537,9 @@ def get_domain_records(
 
             ignore_row_if = domain_kwargs["ignore_row_if"]
             if ignore_row_if == "all_values_are_missing":
-                selectable = (
+                selectable = get_sqlalchemy_selectable(
                     sa.select([sa.text("*")])
-                    .select_from(selectable)
+                    .select_from(get_sqlalchemy_selectable(selectable))
                     .where(
                         sa.not_(
                             sa.and_(
@@ -551,9 +552,9 @@ def get_domain_records(
                     )
                 )
             elif ignore_row_if == "any_value_is_missing":
-                selectable = (
+                selectable = get_sqlalchemy_selectable(
                     sa.select([sa.text("*")])
-                    .select_from(selectable)
+                    .select_from(get_sqlalchemy_selectable(selectable))
                     .where(
                         sa.not_(
                             sa.or_(
diff --git a/great_expectations/util.py b/great_expectations/util.py
--- a/great_expectations/util.py
+++ b/great_expectations/util.py
@@ -1125,3 +1125,13 @@ def get_sqlalchemy_selectable(selectable: Union[Table, Select]) -> Union[Table,
         if isinstance(selectable, Select):
             selectable = selectable.subquery()
     return selectable
+
+
+def get_sqlalchemy_domain_data(domain_data):
+    if version.parse(sa.__version__) < version.parse("1.4"):
+        # Implicit coercion of SELECT and SELECT constructs is deprecated since 1.4
+        # select(query).subquery() should be used instead
+        domain_data = sa.select(["*"]).select_from(domain_data)
+    # engine.get_domain_records returns a valid select object;
+    # calling fetchall at execution is equivalent to a SELECT *
+    return domain_data


Test patch:
diff --git a/tests/execution_engine/test_sqlalchemy_execution_engine.py b/tests/execution_engine/test_sqlalchemy_execution_engine.py
--- a/tests/execution_engine/test_sqlalchemy_execution_engine.py
+++ b/tests/execution_engine/test_sqlalchemy_execution_engine.py
@@ -21,6 +21,10 @@
 
 # Function to test for spark dataframe equality
 from great_expectations.self_check.util import build_sa_engine
+from great_expectations.util import (
+    get_sqlalchemy_domain_data,
+    get_sqlalchemy_selectable,
+)
 from great_expectations.validator.metric_configuration import MetricConfiguration
 from tests.expectations.test_util import get_table_columns_metric
 from tests.test_utils import get_sqlite_table_names, get_sqlite_temp_table_names
@@ -247,7 +251,7 @@ def test_get_domain_records_with_column_domain(sa):
             "condition_parser": "great_expectations__experimental__",
         }
     )
-    domain_data = engine.engine.execute(sa.select(["*"]).select_from(data)).fetchall()
+    domain_data = engine.engine.execute(get_sqlalchemy_domain_data(data)).fetchall()
 
     expected_column_df = df.iloc[:3]
     engine = build_sa_engine(expected_column_df, sa)
@@ -326,7 +330,7 @@ def test_get_domain_records_with_column_pair_domain(sa):
             "ignore_row_if": "neither",
         }
     )
-    domain_data = engine.engine.execute(sa.select(["*"]).select_from(data)).fetchall()
+    domain_data = engine.engine.execute(get_sqlalchemy_domain_data(data)).fetchall()
 
     expected_column_pair_df = pd.DataFrame(
         {
@@ -561,7 +565,7 @@ def test_get_compute_domain_with_unmeetable_row_condition(sa):
         .select_from(engine.active_batch_data.selectable)
         .where(sa.column("b") > 24)
     ).fetchall()
-    domain_data = engine.engine.execute(sa.select(["*"]).select_from(data)).fetchall()
+    domain_data = engine.engine.execute(get_sqlalchemy_domain_data(data)).fetchall()
 
     # Ensuring that column domain is now an accessor kwarg, and data remains unmodified
     assert raw_data == domain_data, "Data does not match after getting compute domain"
@@ -594,7 +598,7 @@ def test_get_compute_domain_with_ge_experimental_condition_parser(sa):
         .select_from(engine.active_batch_data.selectable)
         .where(sa.column("b") == 2)
     ).fetchall()
-    domain_data = engine.engine.execute(sa.select(["*"]).select_from(data)).fetchall()
+    domain_data = engine.engine.execute(get_sqlalchemy_domain_data(data)).fetchall()
 
     # Ensuring that column domain is now an accessor kwarg, and data remains unmodified
     assert raw_data == domain_data, "Data does not match after getting compute domain"