Skip to content

Commit

Permalink
[FEATURE] Add support for returning fully-qualified parameters names/…
Browse files Browse the repository at this point in the history
…values from RuleOutput object (#4773)
  • Loading branch information
alexsherstinsky committed Apr 6, 2022
1 parent fbfe8bd commit eda88d4
Show file tree
Hide file tree
Showing 8 changed files with 596 additions and 28 deletions.
78 changes: 74 additions & 4 deletions great_expectations/rule_based_profiler/rule/rule_output.py
@@ -1,11 +1,15 @@
from typing import List, Optional, Union
from typing import Any, Dict, List, Optional

from great_expectations.core import ExpectationConfiguration
from great_expectations.core.batch import Batch, BatchRequestBase
from great_expectations.rule_based_profiler.expectation_configuration_builder import (
ExpectationConfigurationBuilder,
)
from great_expectations.rule_based_profiler.types import Domain, RuleState
from great_expectations.rule_based_profiler.types import (
Domain,
RuleState,
get_fully_qualified_parameter_names,
get_parameter_values_for_fully_qualified_parameter_names,
)


class RuleOutput:
Expand All @@ -27,7 +31,7 @@ def __init__(
def rule_state(self) -> RuleState:
return self._rule_state

def expectation_configurations(self) -> List[ExpectationConfiguration]:
def get_expectation_configurations(self) -> List[ExpectationConfiguration]:
expectation_configurations: List[ExpectationConfiguration] = []

domains: List[Domain] = self.rule_state.domains
Expand All @@ -47,3 +51,69 @@ def expectation_configurations(self) -> List[ExpectationConfiguration]:
)

return expectation_configurations

def get_fully_qualified_parameter_names(self) -> Dict[Domain, List[str]]:
domain: Domain
return {
domain: self.get_fully_qualified_parameter_names_for_domain(domain=domain)
for domain in self.rule_state.domains
}

def get_fully_qualified_parameter_names_for_domain_id(
self, domain_id: str
) -> List[str]:
domains_dict: Dict[str, Domain] = self.rule_state.get_domains_as_dict()
domain: Domain = domains_dict[domain_id]
fully_qualified_parameter_names: List[
str
] = self.get_fully_qualified_parameter_names_for_domain(domain=domain)
return fully_qualified_parameter_names

def get_fully_qualified_parameter_names_for_domain(
self,
domain: Optional[Domain] = None,
) -> List[str]:
fully_qualified_parameter_names: List[
str
] = get_fully_qualified_parameter_names(
domain=domain,
variables=self.rule_state.variables,
parameters=self.rule_state.parameters,
)
return fully_qualified_parameter_names

def get_parameter_values_for_fully_qualified_parameter_names(
self,
) -> Dict[Domain, Dict[str, Any]]:
domain: Domain
return {
domain: self.get_parameter_values_for_fully_qualified_parameter_names_for_domain(
domain=domain
)
for domain in self.rule_state.domains
}

def get_parameter_values_for_fully_qualified_parameter_names_for_domain_id(
self, domain_id: str
) -> Dict[str, Any]:
domains_dict: Dict[str, Domain] = self.rule_state.get_domains_as_dict()
domain: Domain = domains_dict[domain_id]
parameter_values_for_fully_qualified_parameter_names: Dict[
str, Any
] = self.get_parameter_values_for_fully_qualified_parameter_names_for_domain(
domain=domain
)
return parameter_values_for_fully_qualified_parameter_names

def get_parameter_values_for_fully_qualified_parameter_names_for_domain(
self,
domain: Optional[Domain] = None,
) -> Dict[str, Any]:
parameter_values_for_fully_qualified_parameter_names: Dict[
str, Any
] = get_parameter_values_for_fully_qualified_parameter_names(
domain=domain,
variables=self.rule_state.variables,
parameters=self.rule_state.parameters,
)
return parameter_values_for_fully_qualified_parameter_names
23 changes: 5 additions & 18 deletions great_expectations/rule_based_profiler/rule_based_profiler.py
Expand Up @@ -280,18 +280,12 @@ def run(

def expectation_suite_meta(
self,
batch_list: Optional[List[Batch]] = None,
batch_request: Optional[Union[BatchRequestBase, dict]] = None,
force_batch_data: bool = False,
expectation_suite: Optional[ExpectationSuite] = None,
expectation_suite_name: Optional[str] = None,
include_citation: bool = True,
) -> Dict[str, Any]:
"""
Args:
batch_list: Explicit list of Batch objects to supply data at runtime.
batch_request: Explicit batch_request used to supply data at runtime.
force_batch_data: Whether or not to overwrite any existing batch_request value in Builder components.
expectation_suite: An existing ExpectationSuite to update.
expectation_suite_name: A name for returned ExpectationSuite.
include_citation: Whether or not to include the Profiler config in the metadata for the ExpectationSuite produced by the Profiler
Expand All @@ -300,9 +294,6 @@ def expectation_suite_meta(
Dictionary corresponding to meta property of ExpectationSuite using ExpectationConfiguration objects, accumulated from RuleState of every Rule executed.
"""
expectation_suite: ExpectationSuite = self.expectation_suite(
batch_list=batch_list,
batch_request=batch_request,
force_batch_data=force_batch_data,
expectation_suite=expectation_suite,
expectation_suite_name=expectation_suite_name,
include_citation=include_citation,
Expand All @@ -311,18 +302,12 @@ def expectation_suite_meta(

def expectation_suite(
self,
batch_list: Optional[List[Batch]] = None,
batch_request: Optional[Union[BatchRequestBase, dict]] = None,
force_batch_data: bool = False,
expectation_suite: Optional[ExpectationSuite] = None,
expectation_suite_name: Optional[str] = None,
include_citation: bool = True,
) -> ExpectationSuite:
"""
Args:
batch_list: Explicit list of Batch objects to supply data at runtime.
batch_request: Explicit batch_request used to supply data at runtime.
force_batch_data: Whether or not to overwrite any existing batch_request value in Builder components.
expectation_suite: An existing ExpectationSuite to update.
expectation_suite_name: A name for returned ExpectationSuite.
include_citation: Whether or not to include the Profiler config in the metadata for the ExpectationSuite produced by the Profiler
Expand Down Expand Up @@ -351,7 +336,7 @@ def expectation_suite(

expectation_configurations: List[
ExpectationConfiguration
] = self.expectation_configurations()
] = self.get_expectation_configurations()

expectation_configuration: ExpectationConfiguration
for expectation_configuration in expectation_configurations:
Expand All @@ -364,7 +349,7 @@ def expectation_suite(

return expectation_suite

def expectation_configurations(self) -> List[ExpectationConfiguration]:
def get_expectation_configurations(self) -> List[ExpectationConfiguration]:
"""
Returns:
List of ExpectationConfiguration objects, accumulated from RuleState of every Rule executed.
Expand All @@ -375,7 +360,9 @@ def expectation_configurations(self) -> List[ExpectationConfiguration]:
rule_output: RuleOutput
for rule_state in self.rule_states:
rule_output = RuleOutput(rule_state=rule_state)
expectation_configurations.extend(rule_output.expectation_configurations())
expectation_configurations.extend(
rule_output.get_expectation_configurations()
)

return expectation_configurations

Expand Down
7 changes: 6 additions & 1 deletion great_expectations/rule_based_profiler/types/domain.py
Expand Up @@ -55,7 +55,7 @@ def __init__(
):
if isinstance(domain_type, str):
try:
domain_type = MetricDomainTypes[domain_type]
domain_type = MetricDomainTypes(domain_type)
except (TypeError, KeyError) as e:
raise ValueError(
f""" \
Expand Down Expand Up @@ -110,6 +110,11 @@ def __eq__(self, other):
def __ne__(self, other):
return not self.__eq__(other=other)

def __hash__(self) -> int:
"""Overrides the default implementation"""
_result_hash: int = hash(self.id)
return _result_hash

# Adding this property for convenience (also, in the future, arguments may not be all set to their default values).
@property
def id(self) -> str:
Expand Down
Expand Up @@ -570,7 +570,7 @@ def get_fully_qualified_parameter_names(
)
)

return fully_qualified_parameter_names
return sorted(fully_qualified_parameter_names)


def _get_parameter_node_attribute_names(
Expand Down
4 changes: 4 additions & 0 deletions great_expectations/rule_based_profiler/types/rule_state.py
Expand Up @@ -96,6 +96,10 @@ def remove_domain_if_exists(self, domain: Domain) -> None:
self.domains.remove(domain)
self.remove_domain_if_exists(domain=domain)

def get_domains_as_dict(self) -> Dict[str, Domain]:
domain: Domain
return {domain.id: domain for domain in self.domains}

def initialize_parameter_container_for_domain(
self,
domain: Domain,
Expand Down
2 changes: 1 addition & 1 deletion great_expectations/validator/validator.py
Expand Up @@ -463,7 +463,7 @@ def _build_expectation_configuration(
)
expectation_configurations: List[
ExpectationConfiguration
] = profiler.expectation_configurations()
] = profiler.get_expectation_configurations()

configuration = expectation_configurations[0]

Expand Down
19 changes: 16 additions & 3 deletions tests/rule_based_profiler/conftest.py
Expand Up @@ -12,8 +12,10 @@
from great_expectations.rule_based_profiler.expectation_configuration_builder import (
DefaultExpectationConfigurationBuilder,
)
from great_expectations.rule_based_profiler.rule import Rule
from great_expectations.rule_based_profiler.rule import Rule, RuleOutput
from great_expectations.rule_based_profiler.types import (
DOMAIN_KWARGS_PARAMETER_FULLY_QUALIFIED_NAME,
FULLY_QUALIFIED_PARAMETER_NAME_SEPARATOR_CHARACTER,
Domain,
ParameterContainer,
ParameterNode,
Expand Down Expand Up @@ -493,8 +495,9 @@ def rule_without_variables(
domain_builder=ColumnDomainBuilder(data_context=empty_data_context),
expectation_configuration_builders=[
DefaultExpectationConfigurationBuilder(
expectation_type="expect_my_validation"
)
expectation_type="expect_my_validation",
column=f"{DOMAIN_KWARGS_PARAMETER_FULLY_QUALIFIED_NAME}{FULLY_QUALIFIED_PARAMETER_NAME_SEPARATOR_CHARACTER}column",
),
],
)
return rule
Expand Down Expand Up @@ -523,6 +526,16 @@ def rule_state_with_domains_and_parameters(
return rule_state


@pytest.fixture
def rule_output_for_rule_state_with_domains_and_parameters(
rule_state_with_domains_and_parameters,
):
rule_output: RuleOutput = RuleOutput(
rule_state=rule_state_with_domains_and_parameters
)
return rule_output


@pytest.fixture
def profiler_with_placeholder_args(
empty_data_context,
Expand Down

0 comments on commit eda88d4

Please sign in to comment.