Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finalize validations for custom granularities #370

Merged
merged 8 commits into from
Dec 2, 2024
Merged

Conversation

courtneyholcomb
Copy link
Contributor

@courtneyholcomb courtneyholcomb commented Nov 15, 2024

Description

This PR does 2 things:

  • In this PR, we unintentionally made grain_to_date and offset_to_grain fields case sensitive. This needs to be fixed before we can release to core. This PR fixes that.
  • Adds validation errors to block using custom grain on any fields except offset_window. This is due to a product decision we made to prioritize that feature and defer the rest.

Checklist

dbt_semantic_interfaces/transformations/names.py Outdated Show resolved Hide resolved
tests/parsing/test_metric_parsing.py Outdated Show resolved Hide resolved
tests/parsing/test_metric_parsing.py Outdated Show resolved Hide resolved
…t offset_window

We decided to cut scope on custom calendar in the meantime and only enable it for offset_windows. These validations will make that an easy user experience, while still allowing us to easily remove them once we build support.
@courtneyholcomb courtneyholcomb changed the title Fix case sensitivity for grain_to_date and offset_to_grain Finalize validations for custom granularities Nov 26, 2024
Copy link
Contributor

@WilliamDee WilliamDee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woops, missed the case sensitivity thing 🤦

"""Adds custom parsing to the default method."""
data = deepcopy(input)

# Ensure grain_to_date is lowercased
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we lowercase window here too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could but I think the way it's implemented now is less hacky! This one feels less optimal because we have to go through these dict keys that are not typed. But I couldn't use the same strategy as we did for window because grain is just a string, not an object.

expected_substrings = [
"Invalid time granularity",
"Both window and grain_to_date set for cumulative metric. Please set one or the other.",
"Got differing values for `window`",
"Invalid time granularity 'martian_week' in window: '3 martian_weeks'",
"Invalid time granularity 'martian_week' in window: '3 martian_week'",
"Invalid time granularity 'martian_week' in window: '5 martian_week'",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have tests for successful custom grain parsing now that these fails?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes on line 339! That one is successful.

Copy link
Contributor

@theyostalservice theyostalservice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm. Feel free to address my nit or not.

@@ -304,7 +304,7 @@ def test_derived_metric() -> None: # noqa: D
metrics=[
PydanticMetricInput(
name="random_metric",
offset_window=PydanticMetricTimeWindow.parse("3 weeks", custom_granularity_names=()),
offset_window=PydanticMetricTimeWindow.parse("3 weekies"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol

@validate_safely(whats_being_done="running model validation ensuring cumulative metrics are valid")
def validate_manifest(semantic_manifest: SemanticManifestT) -> Sequence[ValidationIssue]: # noqa: D
def validate_manifest(cls, semantic_manifest: SemanticManifestT) -> Sequence[ValidationIssue]: # noqa: D
issues: List[ValidationIssue] = []

custom_granularity_names = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit / premature optimization - why not make this a set here, rather than making it a set inside validate_metric_time_window, which is called every iteration of the for loop in this function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea!

In the process of writing the prior commit, I discovered that type checking was being erased for function parameters if this decorator was used. This commit fixes that.
…n revealed some type errors. This commit fixes those revealed type errors.
Copy link
Contributor

@theyostalservice theyostalservice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the process of writing the prior commit, I discovered that type checking was being erased for function parameters if this decorator was used. This commit fixes that.

Nice work!!! Thank you for this!

clapping otter
(Otter applause)

@@ -28,7 +25,7 @@ class ElementConsistencyRule(SemanticManifestValidationRule[SemanticManifestT],

@staticmethod
@validate_safely(whats_being_done="running model validation ensuring model wide element consistency")
def validate_manifest(semantic_manifest: PydanticSemanticManifest) -> Sequence[ValidationIssue]: # noqa: D
def validate_manifest(semantic_manifest: SemanticManifestT) -> Sequence[ValidationIssue]: # noqa: D
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<3 this

@@ -120,8 +120,10 @@ def validate_manifest(cls, semantic_manifest: SemanticManifestT) -> Sequence[Val
)

if window:
issues += cls.validate_metric_time_window(
metric_context=metric_context, window=window, custom_granularities=custom_granularity_names
issues.extend(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know why the typechecker would accept one of these and not the other, but tbh, I prefer extend here anyway so I'm not going to complain :P

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can't do list += sequence but you CAN pass a sequence into extend()!

@functools.wraps(func)
def wrapper(*args: Any, **kwargs: Any) -> List[ValidationIssue]: # type: ignore
def wrapper(*args: P.args, **kwargs: P.kwargs) -> Sequence[ValidationIssue]: # type: ignore
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noooice!

@courtneyholcomb courtneyholcomb merged commit a860e25 into main Dec 2, 2024
18 checks passed
@courtneyholcomb courtneyholcomb deleted the court/case-sens branch December 2, 2024 22:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants