Skip to content

Commit

Permalink
Merge develop into maintenance/DX-1/DX-440/alexsherstinsky/link/updat…
Browse files Browse the repository at this point in the history
…e_not_imported_mechanism_to_use_scoped_compatibility_modules_instead-2023_06_28-50
  • Loading branch information
github-actions[bot] committed Jun 28, 2023
2 parents 82b3fb6 + 8e4ec20 commit 07c1204
Show file tree
Hide file tree
Showing 4 changed files with 395 additions and 1 deletion.
133 changes: 132 additions & 1 deletion great_expectations/data_context/data_context/abstract_data_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,10 @@
from great_expectations.data_context.store.expectations_store import (
ExpectationsStore,
)
from great_expectations.data_context.store.store import StoreConfigTypedDict
from great_expectations.data_context.store.store import (
DataDocsSiteConfigTypedDict,
StoreConfigTypedDict,
)
from great_expectations.data_context.store.validations_store import ValidationsStore
from great_expectations.data_context.types.resource_identifiers import (
GXCloudIdentifier,
Expand Down Expand Up @@ -547,6 +550,19 @@ def stores(self) -> dict:
def expectations_store_name(self) -> Optional[str]:
return self.variables.expectations_store_name

@expectations_store_name.setter
@public_api
@new_method_or_class(version="0.17.2")
def expectations_store_name(self, value: str) -> None:
"""Set the name of the expectations store.
Args:
value: New value for the expectations store name.
"""

self.variables.expectations_store_name = value
self._save_project_config()

@property
def expectations_store(self) -> ExpectationsStore:
return self.stores[self.expectations_store_name]
Expand All @@ -563,6 +579,18 @@ def evaluation_parameter_store(self) -> EvaluationParameterStore:
def validations_store_name(self) -> Optional[str]:
return self.variables.validations_store_name

@validations_store_name.setter
@public_api
@new_method_or_class(version="0.17.2")
def validations_store_name(self, value: str) -> None:
"""Set the name of the validations store.
Args:
value: New value for the validations store name.
"""
self.variables.validations_store_name = value
self._save_project_config()

@property
def validations_store(self) -> ValidationsStore:
return self.stores[self.validations_store_name]
Expand Down Expand Up @@ -607,6 +635,18 @@ def checkpoint_store_name(self) -> Optional[str]:

raise gx_exceptions.InvalidTopLevelConfigKeyError(error_message)

@checkpoint_store_name.setter
@public_api
@new_method_or_class(version="0.17.2")
def checkpoint_store_name(self, value: str) -> None:
"""Set the name of the checkpoint store.
Args:
value: New value for the checkpoint store name.
"""
self.variables.checkpoint_store_name = value
self._save_project_config()

@property
def checkpoint_store(self) -> CheckpointStore:
checkpoint_store_name: str = self.checkpoint_store_name # type: ignore[assignment]
Expand Down Expand Up @@ -674,6 +714,18 @@ def profiler_store_name(self) -> Optional[str]:

raise gx_exceptions.InvalidTopLevelConfigKeyError(error_message)

@profiler_store_name.setter
@public_api
@new_method_or_class(version="0.17.2")
def profiler_store_name(self, value: str) -> None:
"""Set the name of the profiler store.
Args:
value: New value for the profiler store name.
"""
self.variables.profiler_store_name = value
self._save_project_config()

@property
def profiler_store(self) -> ProfilerStore:
profiler_store_name: Optional[str] = self.profiler_store_name
Expand Down Expand Up @@ -1608,6 +1660,85 @@ def add_store(self, store_name: str, store_config: StoreConfigTypedDict) -> Stor
self._save_project_config()
return store

@public_api
@new_method_or_class(version="0.17.2")
def add_data_docs_site(
self, site_name: str, site_config: DataDocsSiteConfigTypedDict
) -> None:
"""Add a new Data Docs Site to the DataContext.
Example site config dicts can be found in our "Host and share Data Docs" guides.
Args:
site_name: New site name to add.
site_config: Config dict for the new site.
"""
if self.config.data_docs_sites is not None:
if site_name in self.config.data_docs_sites:
raise gx_exceptions.InvalidKeyError(
f"Data Docs Site `{site_name}` already exists in the Data Context."
)

sites = self.config.data_docs_sites
sites[site_name] = site_config
self.variables.data_docs_sites = sites
self._save_project_config()

@public_api
@new_method_or_class(version="0.17.2")
def list_data_docs_sites(
self,
) -> dict[str, DataDocsSiteConfigTypedDict]:
"""List all Data Docs Sites with configurations."""

if self.config.data_docs_sites is None:
return {}
else:
return self.config.data_docs_sites

@public_api
@new_method_or_class(version="0.17.2")
def update_data_docs_site(
self, site_name: str, site_config: DataDocsSiteConfigTypedDict
) -> None:
"""Update an existing Data Docs Site.
Example site config dicts can be found in our "Host and share Data Docs" guides.
Args:
site_name: Site name to update.
site_config: Config dict that replaces the existing.
"""
if self.config.data_docs_sites is not None:
if site_name not in self.config.data_docs_sites:
raise gx_exceptions.InvalidKeyError(
f"Data Docs Site `{site_name}` does not already exist in the Data Context."
)

sites = self.config.data_docs_sites
sites[site_name] = site_config
self.variables.data_docs_sites = sites
self._save_project_config()

@public_api
@new_method_or_class(version="0.17.2")
def delete_data_docs_site(self, site_name: str):
"""Delete an existing Data Docs Site.
Args:
site_name: Site name to delete.
"""
if self.config.data_docs_sites is not None:
if site_name not in self.config.data_docs_sites:
raise gx_exceptions.InvalidKeyError(
f"Data Docs Site `{site_name}` does not already exist in the Data Context."
)

sites = self.config.data_docs_sites
sites.pop(site_name)
self.variables.data_docs_sites = sites
self._save_project_config()

@public_api
@new_method_or_class(version="0.15.48")
def delete_store(self, store_name: str) -> None:
Expand Down
8 changes: 8 additions & 0 deletions great_expectations/data_context/store/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ class StoreConfigTypedDict(TypedDict):
store_backend: dict


class DataDocsSiteConfigTypedDict(TypedDict):
# NOTE: TypeDict values may be incomplete, update as needed
class_name: str
module_name: NotRequired[str]
store_backend: dict
site_index_builder: dict


class Store:
"""A store is responsible for reading and writing Great Expectations objects
to appropriate backends. It provides a generic API that the DataContext can
Expand Down
206 changes: 206 additions & 0 deletions tests/data_context/abstract_data_context/test_data_docs_config_crud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import copy
from unittest import mock

import pytest

import great_expectations.exceptions as gx_exceptions
from great_expectations.data_context import EphemeralDataContext


@pytest.fixture
def new_site_config() -> dict:
return {
"class_name": "SiteBuilder",
"module_name": "great_expectations.render.renderer.site_builder",
"store_backend": {
"module_name": "great_expectations.data_context.store.tuple_store_backend",
"class_name": "TupleFilesystemStoreBackend",
"base_directory": "/my_new_site/",
},
"site_index_builder": {"class_name": "DefaultSiteIndexBuilder"},
}


class TestAddDataDocsSite:
@pytest.mark.unit
def test_add_data_docs_site(
self,
ephemeral_context_with_defaults: EphemeralDataContext,
new_site_config: dict,
):
# Add a new site
new_site_name = "my_new_site"
ephemeral_context_with_defaults.add_data_docs_site(
site_name=new_site_name, site_config=new_site_config
)

# Check that the new site is present
assert new_site_name in ephemeral_context_with_defaults.get_site_names()

@pytest.mark.unit
def test_add_data_docs_site_persists(
self,
ephemeral_context_with_defaults: EphemeralDataContext,
new_site_config: dict,
):
new_site_name = "my_new_site"
with mock.patch(
"great_expectations.data_context.EphemeralDataContext._save_project_config"
) as mock_save_project_config:
ephemeral_context_with_defaults.add_data_docs_site(
site_name=new_site_name, site_config=new_site_config
)

mock_save_project_config.assert_called_once()

@pytest.mark.unit
def test_add_data_docs_site_already_existing_site_raises_exception(
self,
ephemeral_context_with_defaults: EphemeralDataContext,
new_site_config: dict,
):
# Check fixture configuration
existing_site_name = "local_site"
assert existing_site_name in ephemeral_context_with_defaults.get_site_names()

with pytest.raises(gx_exceptions.InvalidKeyError) as e:
new_site_name = existing_site_name
ephemeral_context_with_defaults.add_data_docs_site(
site_name=new_site_name, site_config=new_site_config
)

assert "Data Docs Site `local_site` already exists in the Data Context." in str(
e.value
)


class TestListDataDocsSites:
@pytest.mark.unit
def test_list_data_docs_sites(
self, ephemeral_context_with_defaults: EphemeralDataContext
):
site_names = [
d for d in ephemeral_context_with_defaults.list_data_docs_sites().keys()
]
assert site_names == ["local_site"]


class TestUpdateDataDocsSite:
@pytest.mark.unit
def test_update_data_docs_site(
self,
ephemeral_context_with_defaults: EphemeralDataContext,
new_site_config: dict,
):
# Add a new site
new_site_name = "my_new_site"
ephemeral_context_with_defaults.add_data_docs_site(
site_name=new_site_name, site_config=new_site_config
)

# Update the new site
updated_site_config = copy.deepcopy(new_site_config)
updated_site_config["store_backend"]["base_directory"] = "/my_updated_site/"

ephemeral_context_with_defaults.update_data_docs_site(
new_site_name, updated_site_config
)

# Check the updated site config
sites = ephemeral_context_with_defaults.variables.data_docs_sites
assert (
sites[new_site_name]["store_backend"]["base_directory"]
== "/my_updated_site/"
)

@pytest.mark.unit
def test_update_data_docs_site_persists(
self,
ephemeral_context_with_defaults: EphemeralDataContext,
new_site_config: dict,
):
# Add a new site
new_site_name = "my_new_site"
ephemeral_context_with_defaults.add_data_docs_site(
site_name=new_site_name, site_config=new_site_config
)

# Update the new site
updated_site_config = copy.deepcopy(new_site_config)
updated_site_config["store_backend"]["base_directory"] = "/my_updated_site/"

with mock.patch(
"great_expectations.data_context.EphemeralDataContext._save_project_config"
) as mock_save_project_config:
ephemeral_context_with_defaults.update_data_docs_site(
new_site_name, updated_site_config
)

mock_save_project_config.assert_called_once()

@pytest.mark.unit
def test_update_data_docs_site_missing_site_raises_exception(
self,
ephemeral_context_with_defaults: EphemeralDataContext,
new_site_config: dict,
):
# Check fixture configuration
assert "missing" not in ephemeral_context_with_defaults.get_site_names()

with pytest.raises(gx_exceptions.InvalidKeyError) as e:
ephemeral_context_with_defaults.update_data_docs_site(
site_name="missing", site_config=new_site_config
)

assert (
"Data Docs Site `missing` does not already exist in the Data Context."
in str(e.value)
)


class TestDeleteDataDocsSite:
@pytest.mark.unit
def test_delete_data_docs_site(
self, ephemeral_context_with_defaults: EphemeralDataContext
):
# Check fixture configuration
existing_site_name = "local_site"
assert existing_site_name in ephemeral_context_with_defaults.get_site_names()

ephemeral_context_with_defaults.delete_data_docs_site(existing_site_name)

# Check that the site is no longer present
assert (
existing_site_name not in ephemeral_context_with_defaults.get_site_names()
)

@pytest.mark.unit
def test_delete_data_docs_site_persists(
self, ephemeral_context_with_defaults: EphemeralDataContext
):
# Check fixture configuration
existing_site_name = "local_site"
assert existing_site_name in ephemeral_context_with_defaults.get_site_names()

with mock.patch(
"great_expectations.data_context.EphemeralDataContext._save_project_config"
) as mock_save_project_config:
ephemeral_context_with_defaults.delete_data_docs_site(existing_site_name)

mock_save_project_config.assert_called_once()

@pytest.mark.unit
def test_delete_data_docs_site_missing_site_raises_exception(
self,
ephemeral_context_with_defaults: EphemeralDataContext,
):
# Check fixture configuration
assert "missing" not in ephemeral_context_with_defaults.get_site_names()

with pytest.raises(gx_exceptions.InvalidKeyError) as e:
ephemeral_context_with_defaults.delete_data_docs_site("missing")

assert (
"Data Docs Site `missing` does not already exist in the Data Context."
in str(e.value)
)

0 comments on commit 07c1204

Please sign in to comment.