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/domain_builder/cardinality_checker.py b/great_expectations/rule_based_profiler/domain_builder/cardinality_checker.py
deleted file mode 100644
--- a/great_expectations/rule_based_profiler/domain_builder/cardinality_checker.py
+++ /dev/null
@@ -1,214 +0,0 @@
-import abc
-import enum
-from dataclasses import dataclass
-from typing import Optional, Tuple, Union
-
-from great_expectations.exceptions import ProfilerConfigurationError
-
-
-@dataclass
-class CardinalityLimit(abc.ABC):
-    name: str
-
-
-@dataclass
-class RelativeCardinalityLimit(CardinalityLimit):
-    max_proportion_unique: float
-    metric_name_defining_limit: str = "column.unique_proportion"
-
-
-@dataclass
-class AbsoluteCardinalityLimit(CardinalityLimit):
-    max_unique_values: int
-    metric_name_defining_limit: str = "column.distinct_values.count"
-
-
-class CardinalityLimitMode(enum.Enum):
-    """Preset limits based on unique values (cardinality)
-
-    Defines relative (ratio) and absolute number of records (table rows) that
-    correspond to each cardinality category.
-
-    Used to determine appropriate Expectation configurations based on data.
-    """
-
-    ZERO = AbsoluteCardinalityLimit("ZERO", 0)
-    ONE = AbsoluteCardinalityLimit("ONE", 1)
-    TWO = AbsoluteCardinalityLimit("TWO", 2)
-    VERY_FEW = AbsoluteCardinalityLimit("VERY_FEW", 10)
-    FEW = AbsoluteCardinalityLimit("FEW", 100)
-    SOME = AbsoluteCardinalityLimit("SOME", 1000)
-    MANY = AbsoluteCardinalityLimit("MANY", 10000)
-    VERY_MANY = AbsoluteCardinalityLimit("VERY_MANY", 100000)
-    UNIQUE = RelativeCardinalityLimit("UNIQUE", 1.0)
-    ABS_10 = AbsoluteCardinalityLimit("ABS_10", 10)
-    ABS_100 = AbsoluteCardinalityLimit("ABS_100", 100)
-    ABS_1000 = AbsoluteCardinalityLimit("ABS_1000", 1000)
-    ABS_10_000 = AbsoluteCardinalityLimit("ABS_10_000", int(1e4))
-    ABS_100_000 = AbsoluteCardinalityLimit("ABS_100_000", int(1e5))
-    ABS_1_000_000 = AbsoluteCardinalityLimit("ABS_1_000_000", int(1e6))
-    ABS_10_000_000 = AbsoluteCardinalityLimit("ABS_10_000_000", int(1e7))
-    ABS_100_000_000 = AbsoluteCardinalityLimit("ABS_100_000_000", int(1e8))
-    ABS_1_000_000_000 = AbsoluteCardinalityLimit("ABS_1_000_000_000", int(1e9))
-    REL_0 = RelativeCardinalityLimit("REL_0", 0.0)
-    REL_001 = RelativeCardinalityLimit("REL_001", 1e-5)
-    REL_01 = RelativeCardinalityLimit("REL_01", 1e-4)
-    REL_0_1 = RelativeCardinalityLimit("REL_0_1", 1e-3)
-    REL_1 = RelativeCardinalityLimit("REL_1", 1e-2)
-    REL_10 = RelativeCardinalityLimit("REL_10", 0.10)
-    REL_25 = RelativeCardinalityLimit("REL_25", 0.25)
-    REL_50 = RelativeCardinalityLimit("REL_50", 0.50)
-    REL_75 = RelativeCardinalityLimit("REL_75", 0.75)
-    ONE_PCT = RelativeCardinalityLimit("ONE_PCT", 0.01)
-    TEN_PCT = RelativeCardinalityLimit("TEN_PCT", 0.10)
-
-
-class CardinalityChecker:
-    """Handles cardinality checking given cardinality limit mode and measured value.
-
-    This class also validates cardinality limit settings and converts from
-    various types of settings. You can choose one of the attributes listed
-    below to create an instance.
-
-    Attributes:
-        limit_mode: CardinalityLimitMode or string name of the mode
-            defining the maximum allowable cardinality.
-        max_unique_values: number of max unique rows for a custom
-            cardinality limit.
-        max_proportion_unique: proportion of unique values for a
-            custom cardinality limit.
-    """
-
-    SUPPORTED_CARDINALITY_LIMIT_MODE_CLASSES: Tuple[
-        Union[AbsoluteCardinalityLimit, RelativeCardinalityLimit]
-    ] = (
-        AbsoluteCardinalityLimit,
-        RelativeCardinalityLimit,
-    )
-    SUPPORTED_CARDINALITY_LIMIT_MODE_STRINGS: Tuple[str] = (
-        mode.name for mode in CardinalityLimitMode
-    )
-
-    def __init__(
-        self,
-        limit_mode: Optional[Union[CardinalityLimitMode, str]] = None,
-        max_unique_values: Optional[int] = None,
-        max_proportion_unique: Optional[float] = None,
-    ):
-        self.supported_limit_mode_class_names = (
-            mode.__name__ for mode in self.SUPPORTED_CARDINALITY_LIMIT_MODE_CLASSES
-        )
-
-        self._limit_mode = self._convert_to_cardinality_mode(
-            limit_mode=limit_mode,
-            max_unique_values=max_unique_values,
-            max_proportion_unique=max_proportion_unique,
-        )
-
-    @property
-    def limit_mode(self) -> CardinalityLimitMode:
-        return self._limit_mode
-
-    def cardinality_within_limit(self, metric_value: float) -> bool:
-        """Determine if the cardinality is within configured limit.
-
-        The metric_value supplied should be either a proportion of unique values
-        or number of unique values based on the configured cardinality limit.
-
-        Args:
-            metric_value: int if number of unique values, float if proportion
-                of unique values.
-
-        Returns:
-            boolean of whether the cardinality is within the configured limit
-        """
-        self._validate_metric_value(metric_value=metric_value)
-        if isinstance(self._limit_mode, AbsoluteCardinalityLimit):
-            return metric_value <= self._limit_mode.max_unique_values
-        elif isinstance(self._limit_mode, RelativeCardinalityLimit):
-            return metric_value <= self._limit_mode.max_proportion_unique
-
-    @staticmethod
-    def _validate_metric_value(metric_value: float) -> None:
-        if not isinstance(metric_value, (int, float)):
-            raise ProfilerConfigurationError(
-                f"Value of measured cardinality must be of type int or float, you provided {type(metric_value)}"
-            )
-        if metric_value < 0.00:
-            raise ProfilerConfigurationError(
-                f"Value of cardinality (number of rows or percent unique) should be greater than 0.00, your value is {metric_value}"
-            )
-
-    def _convert_to_cardinality_mode(
-        self,
-        limit_mode: Optional[Union[CardinalityLimitMode, str]] = None,
-        max_unique_values: Optional[int] = None,
-        max_proportion_unique: Optional[float] = None,
-    ) -> Union[AbsoluteCardinalityLimit, RelativeCardinalityLimit]:
-
-        self._validate_input_parameters(
-            limit_mode=limit_mode,
-            max_unique_values=max_unique_values,
-            max_proportion_unique=max_proportion_unique,
-        )
-
-        if limit_mode is not None:
-            if isinstance(limit_mode, str):
-                try:
-                    return CardinalityLimitMode[limit_mode.upper()].value
-                except KeyError:
-                    raise ProfilerConfigurationError(
-                        f"Please specify a supported cardinality mode. Supported cardinality modes are {[member.name for member in CardinalityLimitMode]}"
-                    )
-            else:
-                return limit_mode.value
-        if max_unique_values is not None:
-            return AbsoluteCardinalityLimit(
-                name=f"CUSTOM_ABS_{max_unique_values}",
-                max_unique_values=max_unique_values,
-            )
-        if max_proportion_unique is not None:
-            return RelativeCardinalityLimit(
-                name=f"CUSTOM_REL_{max_proportion_unique}",
-                max_proportion_unique=max_proportion_unique,
-            )
-
-    def _validate_input_parameters(
-        self,
-        limit_mode: Optional[Union[CardinalityLimitMode, str]] = None,
-        max_unique_values: Optional[int] = None,
-        max_proportion_unique: Optional[int] = None,
-    ) -> None:
-        num_supplied_params: int = sum(
-            [
-                0 if param is None else 1
-                for param in (
-                    limit_mode,
-                    max_unique_values,
-                    max_proportion_unique,
-                )
-            ]
-        )
-        if num_supplied_params != 1:
-            raise ProfilerConfigurationError(
-                f"Please pass ONE of the following parameters: limit_mode, max_unique_values, max_proportion_unique, you passed {num_supplied_params} parameters."
-            )
-
-        if limit_mode is not None:
-            if not (
-                isinstance(limit_mode, CardinalityLimitMode)
-                or isinstance(limit_mode, str)
-            ):
-                raise ProfilerConfigurationError(
-                    f"Please specify a supported cardinality limit type, supported classes are {','.join(self.supported_limit_mode_class_names)} and supported strings are {','.join(self.SUPPORTED_CARDINALITY_LIMIT_MODE_STRINGS)}"
-                )
-        if max_unique_values is not None:
-            if not isinstance(max_unique_values, int):
-                raise ProfilerConfigurationError(
-                    f"Please specify an int, you specified a {type(max_unique_values)}"
-                )
-        if max_proportion_unique is not None:
-            if not isinstance(max_proportion_unique, (float, int)):
-                raise ProfilerConfigurationError(
-                    f"Please specify a float or int, you specified a {type(max_proportion_unique)}"
-                )
diff --git a/great_expectations/rule_based_profiler/domain_builder/categorical_column_domain_builder.py b/great_expectations/rule_based_profiler/domain_builder/categorical_column_domain_builder.py
--- a/great_expectations/rule_based_profiler/domain_builder/categorical_column_domain_builder.py
+++ b/great_expectations/rule_based_profiler/domain_builder/categorical_column_domain_builder.py
@@ -1,19 +1,224 @@
-from typing import Dict, List, Optional, Set, Union
+import abc
+import enum
+from dataclasses import dataclass
+from typing import Dict, List, Optional, Set, Tuple, Union
 
 from great_expectations.core.batch import Batch, BatchRequest, RuntimeBatchRequest
+from great_expectations.exceptions import ProfilerConfigurationError
 from great_expectations.execution_engine.execution_engine import MetricDomainTypes
 from great_expectations.rule_based_profiler.domain_builder import DomainBuilder
-from great_expectations.rule_based_profiler.domain_builder.cardinality_checker import (
-    CardinalityChecker,
-    CardinalityLimitMode,
-)
 from great_expectations.rule_based_profiler.types import Domain, ParameterContainer
-from great_expectations.rule_based_profiler.types.domain import (
-    build_domains_from_column_names,
-)
 from great_expectations.validator.metric_configuration import MetricConfiguration
 
 
+@dataclass
+class CardinalityLimit(abc.ABC):
+    name: str
+
+
+@dataclass
+class RelativeCardinalityLimit(CardinalityLimit):
+    max_proportion_unique: float
+    metric_name_defining_limit: str = "column.unique_proportion"
+
+
+@dataclass
+class AbsoluteCardinalityLimit(CardinalityLimit):
+    max_unique_values: int
+    metric_name_defining_limit: str = "column.distinct_values.count"
+
+
+class CardinalityLimitMode(enum.Enum):
+    """Preset limits based on unique values (cardinality)
+
+    Defines relative (ratio) and absolute number of records (table rows) that
+    correspond to each cardinality category.
+
+    Used to determine appropriate Expectation configurations based on data.
+    """
+
+    ZERO = AbsoluteCardinalityLimit("ZERO", 0)
+    ONE = AbsoluteCardinalityLimit("ONE", 1)
+    TWO = AbsoluteCardinalityLimit("TWO", 2)
+    VERY_FEW = AbsoluteCardinalityLimit("VERY_FEW", 10)
+    FEW = AbsoluteCardinalityLimit("FEW", 100)
+    SOME = AbsoluteCardinalityLimit("SOME", 1000)
+    MANY = AbsoluteCardinalityLimit("MANY", 10000)
+    VERY_MANY = AbsoluteCardinalityLimit("VERY_MANY", 100000)
+    UNIQUE = RelativeCardinalityLimit("UNIQUE", 1.0)
+    ABS_10 = AbsoluteCardinalityLimit("ABS_10", 10)
+    ABS_100 = AbsoluteCardinalityLimit("ABS_100", 100)
+    ABS_1000 = AbsoluteCardinalityLimit("ABS_1000", 1000)
+    ABS_10_000 = AbsoluteCardinalityLimit("ABS_10_000", int(1e4))
+    ABS_100_000 = AbsoluteCardinalityLimit("ABS_100_000", int(1e5))
+    ABS_1_000_000 = AbsoluteCardinalityLimit("ABS_1_000_000", int(1e6))
+    ABS_10_000_000 = AbsoluteCardinalityLimit("ABS_10_000_000", int(1e7))
+    ABS_100_000_000 = AbsoluteCardinalityLimit("ABS_100_000_000", int(1e8))
+    ABS_1_000_000_000 = AbsoluteCardinalityLimit("ABS_1_000_000_000", int(1e9))
+    REL_0 = RelativeCardinalityLimit("REL_0", 0.0)
+    REL_001 = RelativeCardinalityLimit("REL_001", 1e-5)
+    REL_01 = RelativeCardinalityLimit("REL_01", 1e-4)
+    REL_0_1 = RelativeCardinalityLimit("REL_0_1", 1e-3)
+    REL_1 = RelativeCardinalityLimit("REL_1", 1e-2)
+    REL_10 = RelativeCardinalityLimit("REL_10", 0.10)
+    REL_25 = RelativeCardinalityLimit("REL_25", 0.25)
+    REL_50 = RelativeCardinalityLimit("REL_50", 0.50)
+    REL_75 = RelativeCardinalityLimit("REL_75", 0.75)
+    ONE_PCT = RelativeCardinalityLimit("ONE_PCT", 0.01)
+    TEN_PCT = RelativeCardinalityLimit("TEN_PCT", 0.10)
+
+
+class CardinalityChecker:
+    """Handles cardinality checking given cardinality limit mode and measured value.
+
+    This class also validates cardinality limit settings and converts from
+    various types of settings. You can choose one of the attributes listed
+    below to create an instance.
+
+    Attributes:
+        limit_mode: CardinalityLimitMode or string name of the mode
+            defining the maximum allowable cardinality.
+        max_unique_values: number of max unique rows for a custom
+            cardinality limit.
+        max_proportion_unique: proportion of unique values for a
+            custom cardinality limit.
+    """
+
+    SUPPORTED_CARDINALITY_LIMIT_MODE_CLASSES: Tuple[
+        Union[AbsoluteCardinalityLimit, RelativeCardinalityLimit]
+    ] = (
+        AbsoluteCardinalityLimit,
+        RelativeCardinalityLimit,
+    )
+    SUPPORTED_CARDINALITY_LIMIT_MODE_STRINGS: Tuple[str] = (
+        mode.name for mode in CardinalityLimitMode
+    )
+
+    def __init__(
+        self,
+        limit_mode: Optional[Union[CardinalityLimitMode, str]] = None,
+        max_unique_values: Optional[int] = None,
+        max_proportion_unique: Optional[float] = None,
+    ):
+        self.supported_limit_mode_class_names = (
+            mode.__name__ for mode in self.SUPPORTED_CARDINALITY_LIMIT_MODE_CLASSES
+        )
+
+        self._limit_mode = self._convert_to_cardinality_mode(
+            limit_mode=limit_mode,
+            max_unique_values=max_unique_values,
+            max_proportion_unique=max_proportion_unique,
+        )
+
+    @property
+    def limit_mode(self) -> CardinalityLimitMode:
+        return self._limit_mode
+
+    def cardinality_within_limit(self, metric_value: float) -> bool:
+        """Determine if the cardinality is within configured limit.
+
+        The metric_value supplied should be either a proportion of unique values
+        or number of unique values based on the configured cardinality limit.
+
+        Args:
+            metric_value: int if number of unique values, float if proportion
+                of unique values.
+
+        Returns:
+            boolean of whether the cardinality is within the configured limit
+        """
+        self._validate_metric_value(metric_value=metric_value)
+        if isinstance(self._limit_mode, AbsoluteCardinalityLimit):
+            return metric_value <= self._limit_mode.max_unique_values
+        elif isinstance(self._limit_mode, RelativeCardinalityLimit):
+            return metric_value <= self._limit_mode.max_proportion_unique
+
+    @staticmethod
+    def _validate_metric_value(metric_value: float) -> None:
+        if not isinstance(metric_value, (int, float)):
+            raise ProfilerConfigurationError(
+                f"Value of measured cardinality must be of type int or float, you provided {type(metric_value)}"
+            )
+        if metric_value < 0.00:
+            raise ProfilerConfigurationError(
+                f"Value of cardinality (number of rows or percent unique) should be greater than 0.00, your value is {metric_value}"
+            )
+
+    def _convert_to_cardinality_mode(
+        self,
+        limit_mode: Optional[Union[CardinalityLimitMode, str]] = None,
+        max_unique_values: Optional[int] = None,
+        max_proportion_unique: Optional[float] = None,
+    ) -> Union[AbsoluteCardinalityLimit, RelativeCardinalityLimit]:
+
+        self._validate_input_parameters(
+            limit_mode=limit_mode,
+            max_unique_values=max_unique_values,
+            max_proportion_unique=max_proportion_unique,
+        )
+
+        if limit_mode is not None:
+            if isinstance(limit_mode, str):
+                try:
+                    return CardinalityLimitMode[limit_mode.upper()].value
+                except KeyError:
+                    raise ProfilerConfigurationError(
+                        f"Please specify a supported cardinality mode. Supported cardinality modes are {[member.name for member in CardinalityLimitMode]}"
+                    )
+            else:
+                return limit_mode.value
+        if max_unique_values is not None:
+            return AbsoluteCardinalityLimit(
+                name=f"CUSTOM_ABS_{max_unique_values}",
+                max_unique_values=max_unique_values,
+            )
+        if max_proportion_unique is not None:
+            return RelativeCardinalityLimit(
+                name=f"CUSTOM_REL_{max_proportion_unique}",
+                max_proportion_unique=max_proportion_unique,
+            )
+
+    def _validate_input_parameters(
+        self,
+        limit_mode: Optional[Union[CardinalityLimitMode, str]] = None,
+        max_unique_values: Optional[int] = None,
+        max_proportion_unique: Optional[int] = None,
+    ) -> None:
+        num_supplied_params: int = sum(
+            [
+                0 if param is None else 1
+                for param in (
+                    limit_mode,
+                    max_unique_values,
+                    max_proportion_unique,
+                )
+            ]
+        )
+        if num_supplied_params != 1:
+            raise ProfilerConfigurationError(
+                f"Please pass ONE of the following parameters: limit_mode, max_unique_values, max_proportion_unique, you passed {num_supplied_params} parameters."
+            )
+
+        if limit_mode is not None:
+            if not (
+                isinstance(limit_mode, CardinalityLimitMode)
+                or isinstance(limit_mode, str)
+            ):
+                raise ProfilerConfigurationError(
+                    f"Please specify a supported cardinality limit type, supported classes are {','.join(self.supported_limit_mode_class_names)} and supported strings are {','.join(self.SUPPORTED_CARDINALITY_LIMIT_MODE_STRINGS)}"
+                )
+        if max_unique_values is not None:
+            if not isinstance(max_unique_values, int):
+                raise ProfilerConfigurationError(
+                    f"Please specify an int, you specified a {type(max_unique_values)}"
+                )
+        if max_proportion_unique is not None:
+            if not isinstance(max_proportion_unique, (float, int)):
+                raise ProfilerConfigurationError(
+                    f"Please specify a float or int, you specified a {type(max_proportion_unique)}"
+                )
+
+
 class CategoricalColumnDomainBuilder(DomainBuilder):
     """
     This DomainBuilder uses column cardinality to identify domains.
@@ -124,11 +329,18 @@ def _get_domains(
             metrics_for_cardinality_check=metrics_for_cardinality_check,
         )
 
-        column_domains: List[Domain] = build_domains_from_column_names(
-            candidate_column_names
-        )
+        column_name: str
+        domains: List[Domain] = [
+            Domain(
+                domain_type=self.domain_type,
+                domain_kwargs={
+                    "column": column_name,
+                },
+            )
+            for column_name in candidate_column_names
+        ]
 
-        return column_domains
+        return domains
 
     def _get_table_column_names_from_active_batch(
         self,
diff --git a/great_expectations/rule_based_profiler/types/domain.py b/great_expectations/rule_based_profiler/types/domain.py
--- a/great_expectations/rule_based_profiler/types/domain.py
+++ b/great_expectations/rule_based_profiler/types/domain.py
@@ -1,7 +1,7 @@
 import json
 from dataclasses import asdict, dataclass
 from enum import Enum
-from typing import Any, Dict, List, Optional, Union
+from typing import Any, Dict, Optional, Union
 
 from great_expectations.core import IDDict
 from great_expectations.core.util import convert_to_json_serializable
@@ -141,26 +141,3 @@ def _convert_dictionaries_to_domain_kwargs(
                 source[key] = self._convert_dictionaries_to_domain_kwargs(source=value)
 
         return source
-
-
-def build_domains_from_column_names(column_names: List[str]) -> List[Domain]:
-    """Build column type domains from column names.
-
-    Args:
-        column_names: List of columns to convert.
-
-    Returns:
-        A list of column type Domain objects built from column names.
-    """
-    column_name: str
-    domains: List[Domain] = [
-        Domain(
-            domain_type=MetricDomainTypes.COLUMN,
-            domain_kwargs={
-                "column": column_name,
-            },
-        )
-        for column_name in column_names
-    ]
-
-    return domains


Test patch:
diff --git a/tests/rule_based_profiler/domain_builder/test_cardinality_checker.py b/tests/rule_based_profiler/domain_builder/test_cardinality_checker.py
--- a/tests/rule_based_profiler/domain_builder/test_cardinality_checker.py
+++ b/tests/rule_based_profiler/domain_builder/test_cardinality_checker.py
@@ -3,7 +3,7 @@
 import pytest
 
 from great_expectations.exceptions import ProfilerConfigurationError
-from great_expectations.rule_based_profiler.domain_builder.cardinality_checker import (
+from great_expectations.rule_based_profiler.domain_builder.categorical_column_domain_builder import (
     AbsoluteCardinalityLimit,
     CardinalityChecker,
     CardinalityLimitMode,