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/rule_based_profiler/attributed_resolved_metrics.py b/great_expectations/rule_based_profiler/attributed_resolved_metrics.py
--- a/great_expectations/rule_based_profiler/attributed_resolved_metrics.py
+++ b/great_expectations/rule_based_profiler/attributed_resolved_metrics.py
@@ -1,6 +1,6 @@
 import logging
 from dataclasses import asdict, dataclass
-from typing import Any, Dict, Iterator, List, Optional, Sized
+from typing import Dict, Iterator, List, Optional, Sized
 
 import numpy as np
 import pandas as pd
@@ -62,7 +62,7 @@ def _detect_illegal_array_type_or_shape(values: MetricValues) -> bool:
                     if all(isinstance(value, (list, tuple)) for value in values):
                         values_iterator = iter(values)
                         first_value_length: int = len(next(values_iterator))
-                        current_value: Sized[Any]
+                        current_value: Sized
                         if not all(
                             len(current_value) == first_value_length
                             for current_value in values_iterator
@@ -148,11 +148,14 @@ def add_resolved_metric(self, batch_id: str, value: MetricValue) -> None:
 
     @property
     def id(self) -> str:
+        if self.metric_attributes is None:
+            return ""
+
         return self.metric_attributes.to_id()
 
     @property
     def attributed_metric_values(self) -> Optional[Dict[str, MetricValue]]:
-        if self.metric_values_by_batch_id is None:
+        if self.metric_values_by_batch_id is None or self.batch_ids is None:
             return None
 
         batch_id: str
@@ -164,12 +167,18 @@ def attributed_metric_values(self) -> Optional[Dict[str, MetricValue]]:
 
     @property
     def conditioned_attributed_metric_values(self) -> Dict[str, MetricValues]:
+        if self.attributed_metric_values is None:
+            return {}
+
         return AttributedResolvedMetrics.get_conditioned_attributed_metric_values_from_attributed_metric_values(
             attributed_metric_values=self.attributed_metric_values
         )
 
     @property
     def conditioned_metric_values(self) -> MetricValues:
+        if self.attributed_metric_values is None:
+            return None
+
         return AttributedResolvedMetrics.get_conditioned_metric_values_from_attributed_metric_values(
             attributed_metric_values=self.attributed_metric_values
         )
diff --git a/great_expectations/rule_based_profiler/parameter_builder/numeric_metric_range_multi_batch_parameter_builder.py b/great_expectations/rule_based_profiler/parameter_builder/numeric_metric_range_multi_batch_parameter_builder.py
--- a/great_expectations/rule_based_profiler/parameter_builder/numeric_metric_range_multi_batch_parameter_builder.py
+++ b/great_expectations/rule_based_profiler/parameter_builder/numeric_metric_range_multi_batch_parameter_builder.py
@@ -100,6 +100,10 @@ class NumericMetricRangeMultiBatchParameterBuilder(MetricMultiBatchParameterBuil
         "upper_bound",
     }
 
+    METRIC_NAMES_EXEMPT_FROM_VALUE_ROUNDING: set = {
+        "column.unique_proportion",
+    }
+
     exclude_field_names: Set[
         str
     ] = MetricMultiBatchParameterBuilder.exclude_field_names | {
@@ -360,7 +364,11 @@ def _build_parameters(
         ]
 
         round_decimals: int
-        if integer_semantic_domain_type(domain=domain):
+        if (
+            self.metric_name
+            not in NumericMetricRangeMultiBatchParameterBuilder.METRIC_NAMES_EXEMPT_FROM_VALUE_ROUNDING
+            and integer_semantic_domain_type(domain=domain)
+        ):
             round_decimals = 0
         else:
             round_decimals = self._get_round_decimals_using_heuristics(
diff --git a/great_expectations/validator/metrics_calculator.py b/great_expectations/validator/metrics_calculator.py
--- a/great_expectations/validator/metrics_calculator.py
+++ b/great_expectations/validator/metrics_calculator.py
@@ -78,9 +78,12 @@ def head(
         Convenience method to run "table.head" metric.
         """
         if domain_kwargs is None:
-            domain_kwargs = {
-                "batch_id": self._execution_engine.batch_manager.active_batch_data_id,
-            }
+            domain_kwargs = {}
+
+        if domain_kwargs.get("batch_id") is None:
+            domain_kwargs[
+                "batch_id"
+            ] = self._execution_engine.batch_manager.active_batch_id
 
         data: Any = self.get_metric(
             metric=MetricConfiguration(


Test patch:
diff --git a/tests/rule_based_profiler/data_assistant/test_onboarding_data_assistant_happy_paths.py b/tests/rule_based_profiler/data_assistant/test_onboarding_data_assistant_happy_paths.py
--- a/tests/rule_based_profiler/data_assistant/test_onboarding_data_assistant_happy_paths.py
+++ b/tests/rule_based_profiler/data_assistant/test_onboarding_data_assistant_happy_paths.py
@@ -389,8 +389,8 @@ def test_sql_happy_path_onboarding_data_assistant_null_column_quantiles_metric_v
 
 
 @pytest.mark.integration
-@pytest.mark.slow  # 25.51 seconds
-def test_sql_happy_path_onboarding_data_assistant_mixed_decimal_float_column_unique_proportion_metric_values(
+@pytest.mark.slow  # 26.57 seconds
+def test_sql_happy_path_onboarding_data_assistant_mixed_decimal_float_and_boolean_column_unique_proportion_metric_values(
     sa,
     empty_data_context,
 ) -> None:
@@ -475,6 +475,22 @@ def test_sql_happy_path_onboarding_data_assistant_mixed_decimal_float_column_uni
     )
     assert len(result.metrics_by_domain) == 49
     assert len(result.expectation_configurations) == 171
+    assert list(
+        filter(
+            lambda element: element.expectation_type
+            == "expect_column_proportion_of_unique_values_to_be_between"
+            and element.kwargs["column"] == "test_bool",
+            result.get_expectation_suite(
+                send_usage_event=False
+            ).get_column_expectations(),
+        )
+    )[0].kwargs == {
+        "column": "test_bool",
+        "min_value": 0.001002004008016032,
+        "strict_max": False,
+        "max_value": 0.5,
+        "strict_min": False,
+    }
 
 
 def load_data_into_postgres_database(sa):