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/checkpoint/checkpoint.py b/great_expectations/checkpoint/checkpoint.py
--- a/great_expectations/checkpoint/checkpoint.py
+++ b/great_expectations/checkpoint/checkpoint.py
@@ -88,6 +88,17 @@ def _does_validation_contain_batch_request(
     return False
 
 
+def _does_validation_contain_expectation_suite_name(
+    validations: Optional[List[dict]] = None,
+) -> bool:
+    if validations is not None:
+        for val in validations:
+            if val.get("expectation_suite_name") is not None:
+                return True
+
+    return False
+
+
 class BaseCheckpoint(ConfigPeer):
     """
     BaseCheckpoint class is initialized from CheckpointConfig typed object and contains all functionality
@@ -173,20 +184,34 @@ def run(
         Returns:
             CheckpointResult
         """
+        if (
+            sum(bool(x) for x in [self._validator is not None, validator is not None])
+            > 1
+        ):
+            raise gx_exceptions.CheckpointError(
+                f'Checkpoint "{self.name}" has already been created with a validator and overriding it through run() is not allowed.'
+            )
+
         if validator:
-            if self._validator:
-                raise gx_exceptions.CheckpointError(
-                    f'Checkpoint "{self.name}" has already been created with a validator and overriding it through run() is not allowed.'
-                )
+            self._validator = validator
 
+        if self._validator:
             if batch_request or _does_validation_contain_batch_request(
                 validations=validations
             ):
                 raise gx_exceptions.CheckpointError(
-                    f'Checkpoint "{self.name}" has already been created with a validator and overriding it by supplying batch_request and/or validations with a batch_request to run() is not allowed.'
+                    f'Checkpoint "{self.name}" has already been created with a validator and overriding it by supplying a batch_request and/or validations with a batch_request to run() is not allowed.'
                 )
 
-            self._validator = validator
+            if (
+                expectation_suite_name
+                or _does_validation_contain_expectation_suite_name(
+                    validations=validations
+                )
+            ):
+                raise gx_exceptions.CheckpointError(
+                    f'Checkpoint "{self.name}" has already been created with a validator and overriding its expectation_suite_name by supplying an expectation_suite_name and/or validations with an expectation_suite_name to run() is not allowed.'
+                )
 
         if (run_id and run_name) or (run_id and run_time):
             raise gx_exceptions.InvalidCheckpointConfigError(
@@ -726,13 +751,25 @@ def __init__(
         expectation_suite_ge_cloud_id: Optional[str] = None,
         default_validation_id: Optional[str] = None,
     ) -> None:
-        if validator and (
-            batch_request
-            or _does_validation_contain_batch_request(validations=validations)
-        ):
-            raise gx_exceptions.CheckpointError(
-                f'Checkpoint "{name}" cannot be called with a validator and contain a batch_request and/or a batch_request in validations.'
-            )
+        if validator:
+            if batch_request or _does_validation_contain_batch_request(
+                validations=validations
+            ):
+                raise gx_exceptions.CheckpointError(
+                    f'Checkpoint "{name}" cannot be called with a validator and contain a batch_request and/or a batch_request in validations.'
+                )
+
+            if (
+                expectation_suite_name
+                or _does_validation_contain_expectation_suite_name(
+                    validations=validations
+                )
+            ):
+                raise gx_exceptions.CheckpointError(
+                    f'Checkpoint "{name}" cannot be called with a validator and contain an expectation_suite_name and/or an expectation_suite_name in validations.'
+                )
+
+            expectation_suite_name = validator.expectation_suite_name
 
         # Only primitive types are allowed as constructor arguments; data frames are supplied to "run()" as arguments.
         if batch_request_contains_batch_data(batch_request=batch_request):
@@ -782,6 +819,7 @@ def run_with_runtime_args(
         run_name_template: Optional[str] = None,
         expectation_suite_name: Optional[str] = None,
         batch_request: Optional[Union[BatchRequestBase, dict]] = None,
+        validator: Optional[Validator] = None,
         action_list: Optional[List[dict]] = None,
         evaluation_parameters: Optional[dict] = None,
         runtime_configuration: Optional[dict] = None,
@@ -823,6 +861,7 @@ def run_with_runtime_args(
             "run_name_template": run_name_template,
             "expectation_suite_name": expectation_suite_name,
             "batch_request": batch_request,
+            "validator": validator,
             "action_list": action_list,
             "evaluation_parameters": evaluation_parameters,
             "runtime_configuration": runtime_configuration,


Test patch:
diff --git a/tests/checkpoint/test_checkpoint.py b/tests/checkpoint/test_checkpoint.py
--- a/tests/checkpoint/test_checkpoint.py
+++ b/tests/checkpoint/test_checkpoint.py
@@ -56,7 +56,9 @@ def __init__(self) -> None:
 @pytest.fixture
 def dummy_validator() -> Validator:
     class DummyValidator:
-        pass
+        @property
+        def expectation_suite_name(self) -> str:
+            return "my_expectation_suite"
 
     return cast(Validator, DummyValidator())
 
@@ -1554,6 +1556,56 @@ def test_newstyle_checkpoint_raises_error_if_batch_request_in_validations_and_va
         )
 
 
+@pytest.mark.unit
+def test_newstyle_checkpoint_raises_error_if_expectation_suite_name_and_validator_are_specified_in_constructor(
+    dummy_data_context,
+    dummy_validator,
+    batch_request_as_dict,
+    common_action_list,
+):
+    context = dummy_data_context
+    validator = dummy_validator
+
+    with pytest.raises(
+        gx_exceptions.CheckpointError,
+        match=r'Checkpoint "my_checkpoint" cannot be called with a validator and contain an expectation_suite_name and/or an expectation_suite_name in validations.',
+    ):
+        _ = Checkpoint(
+            name="my_checkpoint",
+            data_context=context,
+            config_version=1,
+            run_name_template="%Y-%M-foo-bar-template",
+            expectation_suite_name="my_expectation_suite",
+            validator=validator,
+            action_list=common_action_list,
+        )
+
+
+@pytest.mark.unit
+def test_newstyle_checkpoint_raises_error_if_expectation_suite_name_in_validations_and_validator_are_specified_in_constructor(
+    dummy_data_context,
+    dummy_validator,
+    batch_request_as_dict,
+    common_action_list,
+):
+    context = dummy_data_context
+    validator = dummy_validator
+
+    with pytest.raises(
+        gx_exceptions.CheckpointError,
+        match=r'Checkpoint "my_checkpoint" cannot be called with a validator and contain an expectation_suite_name and/or an expectation_suite_name in validations.',
+    ):
+        _ = Checkpoint(
+            name="my_checkpoint",
+            data_context=context,
+            config_version=1,
+            run_name_template="%Y-%M-foo-bar-template",
+            validator=validator,
+            action_list=common_action_list,
+            validations=[{"expectation_suite_name": "my_expectation_suite"}],
+        )
+
+
 @pytest.mark.integration
 @pytest.mark.slow  # 1.15s
 def test_newstyle_checkpoint_instantiates_and_produces_a_validation_result_when_run_with_validator_specified_in_constructor(
@@ -1573,7 +1625,6 @@ def test_newstyle_checkpoint_instantiates_and_produces_a_validation_result_when_
         data_context=context,
         config_version=1,
         run_name_template="%Y-%M-foo-bar-template",
-        expectation_suite_name="my_expectation_suite",
         validator=validator,
         action_list=common_action_list,
     )
@@ -1585,7 +1636,35 @@ def test_newstyle_checkpoint_instantiates_and_produces_a_validation_result_when_
 
 
 @pytest.mark.unit
-def test_newstyle_checkpoint_raises_error_if_validator_specified_in_constructor_and_validator_are_specified_in_run(
+def test_newstyle_checkpoint_raises_error_if_validator_specified_in_constructor_and_validator_is_specified_in_run(
+    dummy_data_context,
+    dummy_validator,
+    batch_request_as_dict,
+    common_action_list,
+):
+    context = dummy_data_context
+    validator = dummy_validator
+
+    with pytest.raises(gx_exceptions.CheckpointError) as e:
+        _ = Checkpoint(
+            name="my_checkpoint",
+            data_context=context,
+            config_version=1,
+            run_name_template="%Y-%M-foo-bar-template",
+            validator=validator,
+            action_list=common_action_list,
+        ).run(
+            validator=validator,
+        )
+
+    assert (
+        str(e.value)
+        == 'Checkpoint "my_checkpoint" has already been created with a validator and overriding it through run() is not allowed.'
+    )
+
+
+@pytest.mark.unit
+def test_newstyle_checkpoint_raises_error_if_validator_specified_in_constructor_and_batch_request_is_specified_in_run(
     dummy_data_context,
     dummy_validator,
     batch_request_as_dict,
@@ -1600,7 +1679,6 @@ def test_newstyle_checkpoint_raises_error_if_validator_specified_in_constructor_
             data_context=context,
             config_version=1,
             run_name_template="%Y-%M-foo-bar-template",
-            expectation_suite_name="my_expectation_suite",
             validator=validator,
             action_list=common_action_list,
         ).run(
@@ -1640,7 +1718,66 @@ def test_newstyle_checkpoint_raises_error_if_batch_request_is_specified_in_valid
 
     assert (
         str(e.value)
-        == 'Checkpoint "my_checkpoint" has already been created with a validator and overriding it by supplying batch_request and/or validations with a batch_request to run() is not allowed.'
+        == 'Checkpoint "my_checkpoint" has already been created with a validator and overriding it by supplying a batch_request and/or validations with a batch_request to run() is not allowed.'
+    )
+
+
+@pytest.mark.unit
+def test_newstyle_checkpoint_raises_error_if_validator_specified_in_constructor_and_expectation_suite_name_is_specified_in_run(
+    dummy_data_context,
+    dummy_validator,
+    batch_request_as_dict,
+    common_action_list,
+):
+    context = dummy_data_context
+    validator = dummy_validator
+
+    with pytest.raises(gx_exceptions.CheckpointError) as e:
+        _ = Checkpoint(
+            name="my_checkpoint",
+            data_context=context,
+            config_version=1,
+            run_name_template="%Y-%M-foo-bar-template",
+            validator=validator,
+            action_list=common_action_list,
+        ).run(
+            expectation_suite_name="my_expectation_suite",
+        )
+
+    assert (
+        str(e.value)
+        == 'Checkpoint "my_checkpoint" has already been created with a validator and overriding its expectation_suite_name by supplying an expectation_suite_name and/or validations with an expectation_suite_name to run() is not allowed.'
+    )
+
+
+@pytest.mark.unit
+def test_newstyle_checkpoint_raises_error_if_expectation_suite_name_is_specified_in_validations_and_validator_is_specified_in_run(
+    dummy_data_context,
+    dummy_validator,
+    batch_request_as_dict,
+    common_action_list,
+):
+    context = dummy_data_context
+    validator = dummy_validator
+
+    batch_request: BatchRequest = BatchRequest(**batch_request_as_dict)
+    with pytest.raises(gx_exceptions.CheckpointError) as e:
+        _ = Checkpoint(
+            name="my_checkpoint",
+            data_context=context,
+            config_version=1,
+            run_name_template="%Y-%M-foo-bar-template",
+            expectation_suite_name="my_expectation_suite",
+            action_list=common_action_list,
+            validations=[{"batch_request": batch_request}],
+        ).run(
+            batch_request=batch_request_as_dict,
+            validator=validator,
+        )
+
+    assert (
+        str(e.value)
+        == 'Checkpoint "my_checkpoint" has already been created with a validator and overriding it by supplying a batch_request and/or validations with a batch_request to run() is not allowed.'
     )