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/profiler.py b/great_expectations/rule_based_profiler/profiler.py
--- a/great_expectations/rule_based_profiler/profiler.py
+++ b/great_expectations/rule_based_profiler/profiler.py
@@ -43,10 +43,11 @@ def __init__(
             profiler_config: Variables and Rules configuration as a dictionary
             data_context: DataContext object that defines a full runtime environment (data access, etc.)
         """
+        self._profiler_config = profiler_config
         self._data_context = data_context
         self._rules = []
 
-        rules_configs: Dict[str, Dict] = profiler_config.get("rules", {})
+        rules_configs: Dict[str, Dict] = self._profiler_config.get("rules", {})
         rule_name: str
         rule_config: dict
 
@@ -107,7 +108,9 @@ def __init__(
                         )
                     )
 
-            variables_configs: Dict[str, Dict] = profiler_config.get("variables", {})
+            variables_configs: Dict[str, Dict] = self._profiler_config.get(
+                "variables", {}
+            )
             variables: Optional[ParameterContainer] = None
 
             if variables_configs:
@@ -129,10 +132,12 @@ def profile(
         self,
         *,
         expectation_suite_name: Optional[str] = None,
+        include_citation: bool = True,
     ) -> ExpectationSuite:
         """
         Args:
             :param expectation_suite_name: A name for returned Expectation suite.
+            :param include_citation: Whether or not to include the Profiler config in the metadata for the ExpectationSuite produced by the Profiler
         :return: Set of rule evaluation results in the form of an ExpectationSuite
         """
         if expectation_suite_name is None:
@@ -144,6 +149,12 @@ def profile(
             expectation_suite_name=expectation_suite_name
         )
 
+        if include_citation:
+            expectation_suite.add_citation(
+                comment="Suite created by Rule-Based Profiler with the following config",
+                profiler_config=self._profiler_config,
+            )
+
         rule: Rule
         for rule in self._rules:
             expectation_configurations: List[ExpectationConfiguration] = rule.generate()


Test patch:
diff --git a/tests/rule_based_profiler/alice_user_workflow_fixture.py b/tests/rule_based_profiler/alice_user_workflow_fixture.py
--- a/tests/rule_based_profiler/alice_user_workflow_fixture.py
+++ b/tests/rule_based_profiler/alice_user_workflow_fixture.py
@@ -1,6 +1,8 @@
 from typing import Dict, List
 
 import pytest
+from freezegun import freeze_time
+from ruamel.yaml import YAML
 
 from great_expectations.core import ExpectationConfiguration, ExpectationSuite
 
@@ -9,6 +11,7 @@
 
 
 @pytest.fixture
+@freeze_time("09/26/2019 13:42:41")
 def alice_columnar_table_single_batch():
     """
     About the "Alice" User Workflow Fixture
@@ -179,6 +182,13 @@ def alice_columnar_table_single_batch():
     # because the device_ts is ahead of the event_ts for the latest event
     sample_data_relative_path: str = "alice_columnar_table_single_batch_data.csv"
 
+    yaml = YAML()
+    profiler_config: dict = yaml.load(verbose_profiler_config)
+    expected_expectation_suite.add_citation(
+        comment="Suite created by Rule-Based Profiler with the following config",
+        profiler_config=profiler_config,
+    )
+
     return {
         "profiler_config": verbose_profiler_config,
         "expected_expectation_suite_name": expectation_suite_name,
diff --git a/tests/rule_based_profiler/bobby_user_workflow_fixture.py b/tests/rule_based_profiler/bobby_user_workflow_fixture.py
--- a/tests/rule_based_profiler/bobby_user_workflow_fixture.py
+++ b/tests/rule_based_profiler/bobby_user_workflow_fixture.py
@@ -1,6 +1,8 @@
 from typing import List
 
 import pytest
+from freezegun import freeze_time
+from ruamel.yaml import YAML
 
 from great_expectations.core import ExpectationConfiguration, ExpectationSuite
 
@@ -9,6 +11,7 @@
 
 
 @pytest.fixture
+@freeze_time("09/26/2019 13:42:41")
 def bobby_columnar_table_multi_batch():
     """
     # TODO: <Alex>ALEX -- Add DocString</Alex>
@@ -711,6 +714,13 @@ def bobby_columnar_table_multi_batch():
     for expectation_configuration in expectation_configurations:
         expected_expectation_suite.add_expectation(expectation_configuration)
 
+    yaml = YAML()
+    profiler_config: dict = yaml.load(verbose_profiler_config)
+    expected_expectation_suite.add_citation(
+        comment="Suite created by Rule-Based Profiler with the following config",
+        profiler_config=profiler_config,
+    )
+
     return {
         "profiler_config": verbose_profiler_config,
         "expected_expectation_suite_name": expectation_suite_name,
diff --git a/tests/rule_based_profiler/test_profiler.py b/tests/rule_based_profiler/test_profiler.py
--- a/tests/rule_based_profiler/test_profiler.py
+++ b/tests/rule_based_profiler/test_profiler.py
@@ -8,6 +8,7 @@
 from ruamel.yaml import YAML
 
 from great_expectations import DataContext
+from great_expectations.core import ExpectationSuite
 from great_expectations.core.batch import BatchRequest
 from great_expectations.data_context.util import file_relative_path
 from great_expectations.rule_based_profiler.profiler import Profiler
@@ -258,3 +259,57 @@ def test_batches_are_accessible(
             )
         )
         assert metric_value_set == {"category0", "category1", "category2"}
+
+
+def test_profile_includes_citations(
+    alice_columnar_table_single_batch_context,
+    alice_columnar_table_single_batch,
+):
+    # Load data context
+    data_context: DataContext = alice_columnar_table_single_batch_context
+    # Load profiler configs & loop (run tests for each one)
+    yaml_config: str = alice_columnar_table_single_batch["profiler_config"]
+
+    # Instantiate Profiler
+    profiler_config: dict = yaml.load(yaml_config)
+
+    profiler: Profiler = Profiler(
+        profiler_config=profiler_config,
+        data_context=data_context,
+    )
+
+    expectation_suite: ExpectationSuite = profiler.profile(
+        expectation_suite_name=alice_columnar_table_single_batch[
+            "expected_expectation_suite_name"
+        ],
+        include_citation=True,
+    )
+
+    assert len(expectation_suite.meta["citations"]) > 0
+
+
+def test_profile_excludes_citations(
+    alice_columnar_table_single_batch_context,
+    alice_columnar_table_single_batch,
+):
+    # Load data context
+    data_context: DataContext = alice_columnar_table_single_batch_context
+    # Load profiler configs & loop (run tests for each one)
+    yaml_config: str = alice_columnar_table_single_batch["profiler_config"]
+
+    # Instantiate Profiler
+    profiler_config: dict = yaml.load(yaml_config)
+
+    profiler: Profiler = Profiler(
+        profiler_config=profiler_config,
+        data_context=data_context,
+    )
+
+    expectation_suite: ExpectationSuite = profiler.profile(
+        expectation_suite_name=alice_columnar_table_single_batch[
+            "expected_expectation_suite_name"
+        ],
+        include_citation=False,
+    )
+
+    assert expectation_suite.meta.get("citations") is None
diff --git a/tests/rule_based_profiler/test_profiler_user_workflows.py b/tests/rule_based_profiler/test_profiler_user_workflows.py
--- a/tests/rule_based_profiler/test_profiler_user_workflows.py
+++ b/tests/rule_based_profiler/test_profiler_user_workflows.py
@@ -2,6 +2,7 @@
 from typing import Any, Dict, List, cast
 
 import pandas as pd
+from freezegun import freeze_time
 from ruamel.yaml import YAML
 
 from great_expectations import DataContext
@@ -66,6 +67,7 @@ def test_alice_columnar_table_single_batch_batches_are_accessible(
     assert metric_max == 73
 
 
+@freeze_time("09/26/2019 13:42:41")
 def test_alice_profiler_user_workflow_single_batch(
     alice_columnar_table_single_batch_context,
     alice_columnar_table_single_batch,
@@ -87,6 +89,7 @@ def test_alice_profiler_user_workflow_single_batch(
         expectation_suite_name=alice_columnar_table_single_batch[
             "expected_expectation_suite_name"
         ],
+        include_citation=True,
     )
 
     assert (
@@ -161,6 +164,7 @@ def test_bobby_columnar_table_multi_batch_batches_are_accessible(
     assert month == 3
 
 
+@freeze_time("09/26/2019 13:42:41")
 def test_bobby_profiler_user_workflow_multi_batch(
     bobby_columnar_table_multi_batch_context,
     bobby_columnar_table_multi_batch,
@@ -182,6 +186,7 @@ def test_bobby_profiler_user_workflow_multi_batch(
         expectation_suite_name=bobby_columnar_table_multi_batch[
             "expected_expectation_suite_name"
         ],
+        include_citation=True,
     )
 
     assert (