def test_temporal_evaluation_parameters_complex(): # allow 1 second for "now" tolerance now = datetime.now() # Choosing "2*3" == 6 weeks shows we can parse an expression inside a kwarg. assert ((now - timedelta(weeks=2 * 3, seconds=3)) < dateutil.parser.parse( parse_evaluation_parameter("now() - timedelta(weeks=2*3, seconds=2)")) < now - timedelta(weeks=2 * 3, seconds=1))
def test_now_evaluation_parameter(): """ now() is unique in the fact that it is the only evaluation param built-in that has zero arity (takes no arguments). The following tests ensure that it is properly parsed and evaluated in a variety of contexts. """ # By itself res = parse_evaluation_parameter("now()") assert dateutil.parser.parse( res), "Provided evaluation parameter is not dateutil-parseable" # In conjunction with timedelta res = parse_evaluation_parameter("now() - timedelta(weeks=1)") assert dateutil.parser.parse( res), "Provided evaluation parameter is not dateutil-parseable" # Require parens to actually invoke with pytest.raises(EvaluationParameterError): parse_evaluation_parameter("now")
def test_query_store_results_in_evaluation_parameters( data_context_with_query_store): TITANIC_ROW_COUNT = 1313 # taken from the titanic db conftest DISTINCT_TITANIC_ROW_COUNT = 4 # parse_evaluation_parameters correctly resolves a stores URN res1 = parse_evaluation_parameter( parameter_expression= "urn:great_expectations:stores:my_query_store:col_count", evaluation_parameters=None, data_context=data_context_with_query_store, ) assert res1 == TITANIC_ROW_COUNT # and can handle an operator res2 = parse_evaluation_parameter( parameter_expression= "urn:great_expectations:stores:my_query_store:col_count * 2", evaluation_parameters=None, data_context=data_context_with_query_store, ) assert res2 == TITANIC_ROW_COUNT * 2 # can even handle multiple operators res3 = parse_evaluation_parameter( parameter_expression= "urn:great_expectations:stores:my_query_store:col_count * 0 + 100", evaluation_parameters=None, data_context=data_context_with_query_store, ) assert res3 == 100 # allows stores URNs with functions res4 = parse_evaluation_parameter( parameter_expression= "cos(urn:great_expectations:stores:my_query_store:col_count)", evaluation_parameters=None, data_context=data_context_with_query_store, ) assert math.isclose(math.cos(TITANIC_ROW_COUNT), res4) # multiple stores URNs can be used res5 = parse_evaluation_parameter( parameter_expression= "urn:great_expectations:stores:my_query_store:col_count - urn:great_expectations:stores:my_query_store:dist_col_count", evaluation_parameters=None, data_context=data_context_with_query_store, ) assert res5 == TITANIC_ROW_COUNT - DISTINCT_TITANIC_ROW_COUNT # complex expressions can combine operators, urns, and functions res6 = parse_evaluation_parameter( parameter_expression= "abs(-urn:great_expectations:stores:my_query_store:col_count - urn:great_expectations:stores:my_query_store:dist_col_count)", evaluation_parameters=None, data_context=data_context_with_query_store, ) assert res6 == TITANIC_ROW_COUNT + DISTINCT_TITANIC_ROW_COUNT
def test_parse_evaluation_parameter(): # Substitution alone is ok assert parse_evaluation_parameter("a", {"a": 1}) == 1 assert (parse_evaluation_parameter( "urn:great_expectations:validations:blarg", {"urn:great_expectations:validations:blarg": 1}, ) == 1) # Very basic arithmetic is allowed as-is: assert parse_evaluation_parameter("1 + 1", {}) == 2 # So is simple variable substitution: assert parse_evaluation_parameter("a + 1", {"a": 2}) == 3 # URN syntax works assert (parse_evaluation_parameter( "urn:great_expectations:validations:source_patient_data.default" ":expect_table_row_count_to_equal.result.observed_value * 0.9", { "urn:great_expectations:validations:source_patient_data.default" ":expect_table_row_count_to_equal.result.observed_value": 10 }, ) == 9) # bare decimal is accepted assert (parse_evaluation_parameter( "urn:great_expectations:validations:source_patient_data.default" ":expect_table_row_count_to_equal.result.observed_value * .9", { "urn:great_expectations:validations:source_patient_data.default" ":expect_table_row_count_to_equal.result.observed_value": 10 }, ) == 9) # We have basic operations (trunc) assert (parse_evaluation_parameter( "urn:great_expectations:validations:source_patient_data.default" ":expect_table_row_count_to_equal.result.observed_value * 0.9", { "urn:great_expectations:validations:source_patient_data.default" ":expect_table_row_count_to_equal.result.observed_value": 11 }, ) != 9) assert (parse_evaluation_parameter( "trunc(urn:great_expectations:validations:source_patient_data.default" ":expect_table_row_count_to_equal.result.observed_value * 0.9)", { "urn:great_expectations:validations:source_patient_data.default" ":expect_table_row_count_to_equal.result.observed_value": 11 }, ) == 9) # Non GE URN syntax fails with pytest.raises(EvaluationParameterError) as err: parse_evaluation_parameter("urn:ieee:not_ge * 10", {"urn:ieee:not_ge": 1}) assert "Parse Failure" in str(err.value) # Valid variables but invalid expression is no good with pytest.raises(EvaluationParameterError) as err: parse_evaluation_parameter("1 / a", {"a": 0}) assert ( "Error while evaluating evaluation parameter expression: division by zero" in str(err.value)) # It is okay to *substitute* strings in the expression... assert parse_evaluation_parameter("foo", {"foo": "bar"}) == "bar" # ...and to have whitespace in substituted values... assert parse_evaluation_parameter("foo", {"foo": "bar "}) == "bar " # ...but whitespace is *not* preserved from the parameter name if we evaluate it assert parse_evaluation_parameter("foo ", {"foo": "bar"}) == "bar" # NOT "bar " # We can use multiple parameters... assert parse_evaluation_parameter("foo * bar", {"foo": 2, "bar": 3}) == 6 # ...but we cannot leave *partially* evaluated expressions (phew!) with pytest.raises(EvaluationParameterError) as e: parse_evaluation_parameter("foo + bar", {"foo": 2}) assert ( "Error while evaluating evaluation parameter expression: could not convert string to float" in str(e.value))
def test_temporal_evaluation_parameters(): # allow 1 second for "now" tolerance now = datetime.now() assert ((now - timedelta(weeks=1, seconds=3)) < dateutil.parser.parse( parse_evaluation_parameter("now() - timedelta(weeks=1, seconds=2)")) < now - timedelta(weeks=1, seconds=1))
def test_math_evaluation_paramaters(): assert parse_evaluation_parameter("sin(2*PI)") == math.sin(math.pi * 2) assert parse_evaluation_parameter("cos(2*PI)") == math.cos(math.pi * 2) assert parse_evaluation_parameter("tan(2*PI)") == math.tan(math.pi * 2)