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/expectations/metrics/column_aggregate_metrics/column_quantile_values.py b/great_expectations/expectations/metrics/column_aggregate_metrics/column_quantile_values.py
--- a/great_expectations/expectations/metrics/column_aggregate_metrics/column_quantile_values.py
+++ b/great_expectations/expectations/metrics/column_aggregate_metrics/column_quantile_values.py
@@ -21,13 +21,13 @@
 from great_expectations.expectations.metrics.metric_provider import metric_value
 from great_expectations.expectations.metrics.util import attempt_allowing_relative_error
 
+logger = logging.getLogger(__name__)
+
 try:
     from trino.exceptions import TrinoUserError
 except ImportError:
     TrinoUserError = None
 
-logger = logging.getLogger(__name__)
-
 try:
     from sqlalchemy.exc import ProgrammingError
     from sqlalchemy.sql import Select
diff --git a/great_expectations/rule_based_profiler/parameter_builder/metric_multi_batch_parameter_builder.py b/great_expectations/rule_based_profiler/parameter_builder/metric_multi_batch_parameter_builder.py
--- a/great_expectations/rule_based_profiler/parameter_builder/metric_multi_batch_parameter_builder.py
+++ b/great_expectations/rule_based_profiler/parameter_builder/metric_multi_batch_parameter_builder.py
@@ -150,6 +150,10 @@ def _build_parameters(
                     ].conditioned_metric_values,
                     np.ndarray,
                 )
+                and metric_computation_result.attributed_resolved_metrics[
+                    0
+                ].conditioned_metric_values.ndim
+                > 1
                 and metric_computation_result.attributed_resolved_metrics[
                     0
                 ].conditioned_metric_values.shape[1]
diff --git a/great_expectations/rule_based_profiler/types/attributed_resolved_metrics.py b/great_expectations/rule_based_profiler/types/attributed_resolved_metrics.py
--- a/great_expectations/rule_based_profiler/types/attributed_resolved_metrics.py
+++ b/great_expectations/rule_based_profiler/types/attributed_resolved_metrics.py
@@ -21,31 +21,32 @@ def _detect_illegal_array_type_or_shape(values: MetricValues) -> bool:
             return True
 
         if isinstance(values, (list, tuple)):
-            value: MetricValue = values[0]
-            # Python "None" is illegal as candidate for conversion into "numpy.ndarray" type.
-            if value is None:
-                return True
-
-            # Pandas "DataFrame" and "Series" are illegal as candidates for conversion into "numpy.ndarray" type.
-            if isinstance(value, (pd.DataFrame, pd.Series, set)):
-                return True
-
-            if all(isinstance(value, list) for value in values):
-                # Components of different lengths cannot be packaged into "numpy.ndarray" type (due to undefined shape).
-                values_iterator: Iterator = iter(values)
-                first_value_length: int = len(next(values_iterator))
-                current_value: List[Any]
-                if not all(
-                    len(current_value) == first_value_length
-                    for current_value in values_iterator
-                ):
+            if len(values) > 0:
+                value: MetricValue = values[0]
+                # Python "None" is illegal as candidate for conversion into "numpy.ndarray" type.
+                if value is None:
                     return True
 
-            # Recursively evaluate each element of properly shaped iterable (list or tuple).
-            for value in values:
-                if _detect_illegal_array_type_or_shape(values=value):
+                # Pandas "DataFrame" and "Series" are illegal as candidates for conversion into "numpy.ndarray" type.
+                if isinstance(value, (pd.DataFrame, pd.Series, set)):
                     return True
 
+                # Components of different lengths cannot be packaged into "numpy.ndarray" type (due to undefined shape).
+                if all(isinstance(value, list) for value in values):
+                    values_iterator: Iterator = iter(values)
+                    first_value_length: int = len(next(values_iterator))
+                    current_value: List[Any]
+                    if not all(
+                        len(current_value) == first_value_length
+                        for current_value in values_iterator
+                    ):
+                        return True
+
+                # Recursively evaluate each element of properly shaped iterable (list or tuple).
+                for value in values:
+                    if _detect_illegal_array_type_or_shape(values=value):
+                        return True
+
         return False
 
     if _detect_illegal_array_type_or_shape(values=metric_values):
@@ -70,12 +71,12 @@ class AttributedResolvedMetrics(SerializableDictDot):
     @staticmethod
     def get_conditioned_attributed_metric_values_from_attributed_metric_values(
         attributed_metric_values: Dict[str, MetricValues]
-    ) -> Optional[Dict[str, MetricValues]]:
+    ) -> Dict[str, MetricValues]:
         """
         Converts "attributed_metric_values" to Numpy array for each "batch_id" key (recursively, wherever possible).
         """
         if attributed_metric_values is None:
-            return None
+            return {}
 
         batch_id: str
         metric_values: MetricValues


Test patch: