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/validator/validator.py b/great_expectations/validator/validator.py
--- a/great_expectations/validator/validator.py
+++ b/great_expectations/validator/validator.py
@@ -251,7 +251,7 @@ def __getattr__(self, name):
                 f"'{type(self).__name__}'  object has no attribute '{name}'"
             )
 
-    def validate_expectation(self, name: str):
+    def validate_expectation(self, name: str) -> Callable:
         """
         Given the name of an Expectation, obtains the Class-first Expectation implementation and utilizes the
                 expectation's validate method to obtain a validation result. Also adds in the runtime configuration
@@ -270,24 +270,30 @@ def inst_expectation(*args, **kwargs):
             # TODO: JPC - THIS LOGIC DOES NOT RESPECT DEFAULTS SET BY USERS IN THE VALIDATOR VS IN THE EXPECTATION
             # DEVREL has action to develop a new plan in coordination with MarioPod
 
-            basic_default_expectation_args = {
+            expectation_kwargs: dict = recursively_convert_to_json_serializable(kwargs)
+
+            meta: dict = expectation_kwargs.pop("meta", None)
+
+            basic_default_expectation_args: dict = {
                 k: v
                 for k, v in self.default_expectation_args.items()
                 if k in Validator.RUNTIME_KEYS
             }
-            basic_runtime_configuration = copy.deepcopy(basic_default_expectation_args)
+            basic_runtime_configuration: dict = copy.deepcopy(
+                basic_default_expectation_args
+            )
             basic_runtime_configuration.update(
                 {k: v for k, v in kwargs.items() if k in Validator.RUNTIME_KEYS}
             )
 
-            allowed_config_keys = expectation_impl.get_allowed_config_keys()
+            allowed_config_keys: Tuple[str] = expectation_impl.get_allowed_config_keys()
 
-            expectation_kwargs = recursively_convert_to_json_serializable(kwargs)
+            args_keys: Tuple[str] = expectation_impl.args_keys or tuple()
 
-            meta = expectation_kwargs.pop("meta", None)
-
-            args_keys = expectation_impl.args_keys or tuple()
+            arg_name: str
 
+            idx: int
+            arg: Any
             for idx, arg in enumerate(args):
                 try:
                     arg_name = args_keys[idx]
@@ -386,35 +392,6 @@ def _build_expectation_configuration(
         meta: dict,
         expectation_impl: "Expectation",  # noqa: F821
     ) -> ExpectationConfiguration:
-        success_keys: Tuple[str] = (
-            expectation_impl.success_keys
-            if hasattr(expectation_impl, "success_keys")
-            else tuple()
-        )
-        arg_keys: Tuple[str] = (
-            expectation_impl.arg_keys
-            if hasattr(expectation_impl, "arg_keys")
-            else tuple()
-        )
-        runtime_keys: Tuple[str] = (
-            expectation_impl.runtime_keys
-            if hasattr(expectation_impl, "runtime_keys")
-            else None
-        ) or tuple()
-        # noinspection PyTypeChecker
-        override_keys: Tuple[str] = success_keys + arg_keys + runtime_keys
-
-        key: str
-        value: Any
-        expectation_kwargs_overrides: dict = {
-            key: value
-            for key, value in expectation_kwargs.items()
-            if key in override_keys
-        }
-        expectation_kwargs_overrides = convert_to_json_serializable(
-            data=expectation_kwargs_overrides
-        )
-
         auto: Optional[bool] = expectation_kwargs.get("auto")
         profiler_config: Optional[RuleBasedProfilerConfig] = expectation_kwargs.get(
             "profiler_config"
@@ -430,29 +407,14 @@ def _build_expectation_configuration(
 
         configuration: ExpectationConfiguration
 
-        if auto:
-            # Save custom Rule-Based Profiler configuration for reconciling it with optionally-specified default
-            # Rule-Based Profiler configuration as an override argument to "BaseRuleBasedProfiler.run()" method.
-            override_profiler_config: Optional[RuleBasedProfilerConfig]
-            if default_profiler_config:
-                override_profiler_config = copy.deepcopy(profiler_config)
-            else:
-                override_profiler_config = None
-
-            """
-            If default Rule-Based Profiler configuration exists, use it as base with custom Rule-Based Profiler
-            configuration as override; otherwise, use custom Rule-Based Profiler configuration with no override.
-            """
-            profiler_config = default_profiler_config or profiler_config
-
-            profiler: BaseRuleBasedProfiler = self._build_rule_based_profiler(
-                expectation_type=expectation_type,
-                expectation_kwargs=expectation_kwargs,
-                success_keys=success_keys,
-                profiler_config=profiler_config,
-                override_profiler_config=override_profiler_config,
-            )
-
+        profiler: Optional[
+            BaseRuleBasedProfiler
+        ] = self.build_rule_based_profiler_for_expectation(
+            expectation_type=expectation_type
+        )(
+            *(), **expectation_kwargs
+        )
+        if profiler is not None:
             profiler.run(
                 variables=None,
                 rules=None,
@@ -468,6 +430,35 @@ def _build_expectation_configuration(
             configuration = expectation_configurations[0]
 
             # Reconcile explicitly provided "ExpectationConfiguration" success_kwargs as overrides to generated values.
+            success_keys: Tuple[str] = (
+                expectation_impl.success_keys
+                if hasattr(expectation_impl, "success_keys")
+                else tuple()
+            )
+            arg_keys: Tuple[str] = (
+                expectation_impl.arg_keys
+                if hasattr(expectation_impl, "arg_keys")
+                else tuple()
+            )
+            runtime_keys: Tuple[str] = (
+                expectation_impl.runtime_keys
+                if hasattr(expectation_impl, "runtime_keys")
+                else None
+            ) or tuple()
+            # noinspection PyTypeChecker
+            override_keys: Tuple[str] = success_keys + arg_keys + runtime_keys
+
+            key: str
+            value: Any
+            expectation_kwargs_overrides: dict = {
+                key: value
+                for key, value in expectation_kwargs.items()
+                if key in override_keys
+            }
+            expectation_kwargs_overrides = convert_to_json_serializable(
+                data=expectation_kwargs_overrides
+            )
+
             expectation_kwargs = configuration.kwargs
             expectation_kwargs.update(expectation_kwargs_overrides)
 
@@ -490,7 +481,115 @@ def _build_expectation_configuration(
 
         return configuration
 
-    def _build_rule_based_profiler(
+    def build_rule_based_profiler_for_expectation(
+        self, expectation_type: str
+    ) -> Callable:
+        """
+        Given name of Expectation ("expectation_type"), builds effective RuleBasedProfiler object from configuration.
+        Args:
+            expectation_type (str): Name of Expectation for which Rule-Based Profiler may be configured.
+
+        Returns:
+            Function that builds effective RuleBasedProfiler object (for specified "expectation_type").
+        """
+        expectation_impl = get_expectation_impl(expectation_type)
+
+        def inst_rule_based_profiler(
+            *args, **kwargs
+        ) -> Optional[BaseRuleBasedProfiler]:
+            if args is None:
+                args = tuple()
+
+            if kwargs is None:
+                kwargs = {}
+
+            expectation_kwargs: dict = recursively_convert_to_json_serializable(kwargs)
+
+            basic_default_expectation_args: dict = {
+                k: v
+                for k, v in self.default_expectation_args.items()
+                if k in Validator.RUNTIME_KEYS
+            }
+            basic_runtime_configuration: dict = copy.deepcopy(
+                basic_default_expectation_args
+            )
+            basic_runtime_configuration.update(
+                {k: v for k, v in kwargs.items() if k in Validator.RUNTIME_KEYS}
+            )
+
+            allowed_config_keys: Tuple[str] = expectation_impl.get_allowed_config_keys()
+
+            args_keys: Tuple[str] = expectation_impl.args_keys or tuple()
+
+            arg_name: str
+
+            idx: int
+            arg: Any
+            for idx, arg in enumerate(args):
+                try:
+                    arg_name = args_keys[idx]
+                    if arg_name in allowed_config_keys:
+                        expectation_kwargs[arg_name] = arg
+                    if arg_name == "meta":
+                        logger.warning(
+                            "Setting meta via args could be ambiguous; please use a kwarg instead."
+                        )
+                except IndexError:
+                    raise InvalidExpectationConfigurationError(
+                        f"Invalid positional argument: {arg}"
+                    )
+
+            success_keys: Tuple[str] = (
+                expectation_impl.success_keys
+                if hasattr(expectation_impl, "success_keys")
+                else tuple()
+            )
+
+            auto: Optional[bool] = expectation_kwargs.get("auto")
+            profiler_config: Optional[RuleBasedProfilerConfig] = expectation_kwargs.get(
+                "profiler_config"
+            )
+            default_profiler_config: Optional[
+                RuleBasedProfilerConfig
+            ] = expectation_impl.default_kwarg_values.get("profiler_config")
+
+            if auto and profiler_config is None and default_profiler_config is None:
+                raise ValueError(
+                    "Automatic Expectation argument estimation requires a Rule-Based Profiler to be provided."
+                )
+
+            profiler: Optional[BaseRuleBasedProfiler]
+
+            if auto:
+                # Save custom Rule-Based Profiler configuration for reconciling it with optionally-specified default
+                # Rule-Based Profiler configuration as an override argument to "BaseRuleBasedProfiler.run()" method.
+                override_profiler_config: Optional[RuleBasedProfilerConfig]
+                if default_profiler_config:
+                    override_profiler_config = copy.deepcopy(profiler_config)
+                else:
+                    override_profiler_config = None
+
+                """
+                If default Rule-Based Profiler configuration exists, use it as base with custom Rule-Based Profiler
+                configuration as override; otherwise, use custom Rule-Based Profiler configuration with no override.
+                """
+                profiler_config = default_profiler_config or profiler_config
+
+                profiler = self._build_rule_based_profiler_from_config_and_runtime_args(
+                    expectation_type=expectation_type,
+                    expectation_kwargs=expectation_kwargs,
+                    success_keys=success_keys,
+                    profiler_config=profiler_config,
+                    override_profiler_config=override_profiler_config,
+                )
+            else:
+                profiler = None
+
+            return profiler
+
+        return inst_rule_based_profiler
+
+    def _build_rule_based_profiler_from_config_and_runtime_args(
         self,
         expectation_type: str,
         expectation_kwargs: dict,


Test patch: