Repository: great-expectations/great_expectations
Pull request #7031 (2023-02-02 14:12:34)

[MAINTENANCE] Deprecate old `DataContext` CRUD methods
Changes proposed in this pull request:
- Add deprecation messages to any `create_` or `save_` methods


### Definition of Done
- [x] My code follows the Great Expectations [style guide](https://docs.greatexpectations.io/docs/contributing/style_guides/code_style)
- [x] I have performed a [self-review](https://docs.greatexpectations.io/docs/contributing/contributing_checklist) of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have added [unit tests](https://docs.greatexpectations.io/docs/contributing/contributing_test#writing-unit-and-integration-tests) where applicable and made sure that new and existing tests are passing.
- [x] I have run any local integration tests and made sure that nothing is broken.


netlify[bot]: ### <span aria-hidden="true">👷</span> Deploy Preview for *niobium-lead-7998* processing.


|  Name | Link |
|---------------------------------|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 89545192e87a064ffe9384708d6fc44a4d726e63 |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/niobium-lead-7998/deploys/63dbc4d580e28100092921ba |
codesee-maps[bot]: <details>
<summary><b>👇 <a href="https://app.codesee.io/r/reviews?pr=7031&src=https%3A%2F%2Fgithub.com%2Fgreat-expectations%2Fgreat_expectations">Click on the image</a> for a new way to code review</b>
</summary>

  - Make big changes easier — review code in small groups of related files
  - Know where to start — see the whole change at a glance
  - Take a code tour — explore the change with an interactive tour
  - Make comments and review — all fully sync’ed with github

    [Try it now!](https://app.codesee.io/r/reviews?pr=7031&src=https%3A%2F%2Fgithub.com%2Fgreat-expectations%2Fgreat_expectations)
</details>

[![Review these changes using an interactive CodeSee Map](https://s3.us-east-2.amazonaws.com/maps.codesee.io/images/github/great-expectations/great_expectations/7031/c23c08d3/d8cbafcbf3bdcefba6a25cc04419665037208fba.svg)](https://app.codesee.io/r/reviews?pr=7031&src=https%3A%2F%2Fgithub.com%2Fgreat-expectations%2Fgreat_expectations)

#### Legend
![CodeSee Map Legend](https://app.codesee.io/Legend_v2.png)

Patch:
diff --git a/great_expectations/data_context/data_context/abstract_data_context.py b/great_expectations/data_context/data_context/abstract_data_context.py
index c8fba7cd4..f25c23ce9 100644
--- a/great_expectations/data_context/data_context/abstract_data_context.py
+++ b/great_expectations/data_context/data_context/abstract_data_context.py
@@ -332,6 +332,9 @@ class AbstractDataContext(ConfigPeer, ABC):
         self.config.update(project_config)
 
     @public_api
+    @deprecated_method_or_class(
+        version="0.15.48", message="Part of the deprecated DataContext CRUD API"
+    )
     @usage_statistics_enabled_method(
         event_name=UsageStatsEvents.DATA_CONTEXT_SAVE_EXPECTATION_SUITE,
         args_payload_fn=save_expectation_suite_usage_statistics,
@@ -360,6 +363,12 @@ class AbstractDataContext(ConfigPeer, ABC):
         Raises:
             DataContextError: If a suite with the same name exists and `overwrite_existing` is set to `False`.
         """
+        # deprecated-v0.15.48
+        warnings.warn(
+            "save_expectation_suite is deprecated as of v0.15.48 and will be removed in v0.18. "
+            "Please use update_expectation_suite or add_or_update_expectation_suite instead.",
+            DeprecationWarning,
+        )
         return self._save_expectation_suite(
             expectation_suite=expectation_suite,
             expectation_suite_name=expectation_suite_name,
@@ -647,6 +656,9 @@ class AbstractDataContext(ConfigPeer, ABC):
         self._project_config = project_config
         self.variables.config = project_config
 
+    @deprecated_method_or_class(
+        version="0.15.48", message="Part of the deprecated DataContext CRUD API"
+    )
     def save_datasource(
         self, datasource: Union[LegacyDatasource, BaseDatasource]
     ) -> Union[LegacyDatasource, BaseDatasource]:
@@ -664,6 +676,12 @@ class AbstractDataContext(ConfigPeer, ABC):
         Returns:
             The datasource, after storing and retrieving the stored config.
         """
+        # deprecated-v0.15.48
+        warnings.warn(
+            "save_datasource is deprecated as of v0.15.48 and will be removed in v0.18. "
+            "Please use update_datasource or add_or_update_datasource instead.",
+            DeprecationWarning,
+        )
         # Chetan - 20221103 - Directly accessing private attr in order to patch security vulnerabiliy around credential leakage.
         # This is to be removed once substitution logic is migrated from the context to the individual object level.
         config = datasource._raw_config
@@ -1206,6 +1224,9 @@ class AbstractDataContext(ConfigPeer, ABC):
         """
         return RuleBasedProfiler.list_profilers(self.profiler_store)
 
+    @deprecated_method_or_class(
+        version="0.15.48", message="Part of the deprecated DataContext CRUD API"
+    )
     def save_profiler(
         self,
         profiler: RuleBasedProfiler,
@@ -1218,6 +1239,12 @@ class AbstractDataContext(ConfigPeer, ABC):
         Returns:
             The input profiler - may be modified with an id depending on the backing store.
         """
+        # deprecated-v0.15.48
+        warnings.warn(
+            "save_profiler is deprecated as of v0.15.48 and will be removed in v0.18. "
+            "Please use update_profiler or add_or_update_profiler instead.",
+            DeprecationWarning,
+        )
         name = profiler.name
         ge_cloud_id = profiler.ge_cloud_id
         key = self._determine_key_for_profiler_save(name=name, id=ge_cloud_id)
@@ -2091,6 +2118,9 @@ class AbstractDataContext(ConfigPeer, ABC):
         return datasource.get_batch_list_from_batch_request(batch_request=batch_request)
 
     @public_api
+    @deprecated_method_or_class(
+        version="0.15.48", message="Part of the deprecated DataContext CRUD API"
+    )
     def create_expectation_suite(
         self,
         expectation_suite_name: str,
@@ -2135,6 +2165,12 @@ class AbstractDataContext(ConfigPeer, ABC):
             ValueError: The input `overwrite_existing` is of the wrong type.
             DataContextError: A suite with the same name already exists (and `overwrite_existing` is not enabled).
         """
+        # deprecated-v0.15.48
+        warnings.warn(
+            "create_expectation_suite is deprecated as of v0.15.48 and will be removed in v0.18. "
+            "Please use add_expectation_suite or add_or_update_expectation_suite instead.",
+            DeprecationWarning,
+        )
         return self._add_expectation_suite(
             expectation_suite_name=expectation_suite_name,
             overwrite_existing=overwrite_existing,


Test patch:
diff --git a/tests/data_context/test_data_context_deprecation.py b/tests/data_context/test_data_context_deprecation.py
index 0b7bd602c..4767881af 100644
--- a/tests/data_context/test_data_context_deprecation.py
+++ b/tests/data_context/test_data_context_deprecation.py
@@ -1,3 +1,7 @@
+from __future__ import annotations
+
+from unittest import mock
+
 import pytest
 
 from great_expectations.data_context.data_context.base_data_context import (
@@ -9,6 +13,9 @@ from great_expectations.data_context.data_context.cloud_data_context import (
 from great_expectations.data_context.data_context.data_context import (
     _resolve_cloud_args as data_context_resolver,
 )
+from great_expectations.data_context.data_context.ephemeral_data_context import (
+    EphemeralDataContext,
+)
 from great_expectations.data_context.types.base import GXCloudConfig
 from great_expectations.util import _resolve_cloud_args as get_context_resolver
 
@@ -236,3 +243,38 @@ def test_get_context_resolve_cloud_args(
 ):
     actual_resolved_args = get_context_resolver(**cloud_args)
     assert actual_resolved_args == expected_resolved_args
+
+
+@pytest.mark.unit
+@pytest.mark.parametrize(
+    "method_name, required_args",
+    [
+        pytest.param(
+            "save_expectation_suite", ["expectation_suite"], id="save_expectation_suite"
+        ),
+        pytest.param("save_datasource", ["datasource"], id="save_datasource"),
+        pytest.param("save_profiler", ["profiler"], id="save_profiler"),
+        pytest.param(
+            "create_expectation_suite",
+            ["expectation_suite_name"],
+            id="create_expectation_suite",
+        ),
+    ],
+)
+def test_data_context_crud_api_deprecation(
+    in_memory_runtime_context: EphemeralDataContext,
+    method_name: str,
+    required_args: list[str],
+):
+    context = in_memory_runtime_context
+
+    method = getattr(context, method_name)
+    args = {arg: mock.Mock() for arg in required_args}
+
+    with pytest.deprecated_call():
+        try:
+            method(**args)
+        # We only care about triggering the method to ensure deprecation
+        # The actual underlying logic of each method is under test elsewhere in the test suite
+        except Exception:
+            pass