-
Notifications
You must be signed in to change notification settings - Fork 57
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
PythonMutator: support omitempty in PyDABs #1513
Conversation
a8c5352
to
b695d5d
Compare
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #1513 +/- ##
==========================================
+ Coverage 52.25% 53.96% +1.70%
==========================================
Files 317 353 +36
Lines 18004 20544 +2540
==========================================
+ Hits 9408 11086 +1678
- Misses 7903 8653 +750
- Partials 693 805 +112 ☔ View full report in Codecov by Sentry. |
b695d5d
to
fb6c851
Compare
fb6c851
to
b1d8b59
Compare
@@ -311,6 +319,21 @@ func createInitOverrideVisitor(ctx context.Context) merge.OverrideVisitor { | |||
} | |||
} | |||
|
|||
func isOmitemptyDelete(left dyn.Value) bool { | |||
// PyDABs output can omit empty sequences/mappings, because we don't track them as optional, | |||
// there is no semantic difference between empty and missing, so we keep them as they were before. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand correctly with this PR you are trying to fix the case where a value in the original bundle config is an empty (but not nil) sequence or mapping, but pydabs skips emitting the key (with an empty value) in its serialized output. This causes an error (unexpected change at %q (delete)
) which you want to avoid.
Is my understanding of the problem you are trying to solve correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct. We don't distinguish between empty and unset lists, so when the list is empty, we omit it in the output.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change LGTM, but can you elaborate on why we don't treat these as different? If the JSON representation is mapped to a Python data class, I imagine there in fact being a difference between a None
field and an empty list.
@pietern having In cases where it matters, we can still use We can fix it in a different way by tracking which lists were not modified or ever specified explicitly. |
@@ -311,6 +319,21 @@ func createInitOverrideVisitor(ctx context.Context) merge.OverrideVisitor { | |||
} | |||
} | |||
|
|||
func isOmitemptyDelete(left dyn.Value) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
omitempty
is specific to the JSON serializer. Here we check if the incoming value is an empty collection.
Maybe isEmptyCollection
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was intentional because we want to reserve this method to specific behavior with omit empty and add a comment explaining that. For instance, we intentionally don't handle objects where all fields are empty.
libs/dyn/merge/override.go
Outdated
// the final value of the node. 'VisitDelete' should return dyn.NilValue to | ||
// do the delete, or can return 'left' to undo it. | ||
// | ||
// TODO 'VisitDelete' and 'VisitInsert' should support dyn.NilValue as well |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would the semantics be?
I think you mean VisitUpdate
here, not VisitDelete
.
libs/dyn/merge/override.go
Outdated
|
||
if err != nil { | ||
return dyn.NewMapping(), err | ||
} | ||
|
||
// if 'delete' was undone, add it back | ||
if deleteOut != dyn.NilValue { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to check the Kind()
. A nil value may have a location attached to it so direct equality can fail.
libs/dyn/merge/override.go
Outdated
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// if 'delete' was undone, add it back | ||
if out != dyn.NilValue { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above.
@pietern, thanks for the suggestions about using errors. It's much cleaner now, and we don't need to document that insert/update doesn't support this behavior because the error is dedicated to the "delete" method. |
if left.Kind() == dyn.KindNil { | ||
return true | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A switch/case would be cleaner here, IMO.
Co-authored-by: Pieter Noordhuis <[email protected]>
Bundles: As of this release you can interact with bundles when running the CLI on DBR (e.g. via the Web Terminal). * Fix non-default project names not working in dbt-sql template ([#1500](#1500)). * Improve `bundle validate` output ([#1532](#1532)). * Fixed resolving variable references inside slice variable ([#1550](#1550)). * Fixed bundle not loading when empty variable is defined ([#1552](#1552)). * Use `vfs.Path` for filesystem interaction ([#1554](#1554)). * Replace `vfs.Path` with extension-aware filer when running on DBR ([#1556](#1556)). Internal: * merge.Override: Fix handling of dyn.NilValue ([#1530](#1530)). * Compare `.Kind()` instead of direct equality checks on a `dyn.Value` ([#1520](#1520)). * PythonMutator: register product in user agent extra ([#1533](#1533)). * Ignore `dyn.NilValue` when traversing value from `dyn.Map` ([#1547](#1547)). * Add extra tests for the sync block ([#1548](#1548)). * PythonMutator: add diagnostics ([#1531](#1531)). * PythonMutator: support omitempty in PyDABs ([#1513](#1513)). * PythonMutator: allow insert 'resources' and 'resources.jobs' ([#1555](#1555)).
Bundles: As of this release you can interact with bundles when running the CLI on DBR (e.g. via the Web Terminal). * Fix non-default project names not working in dbt-sql template ([#1500](#1500)). * Improve `bundle validate` output ([#1532](#1532)). * Fixed resolving variable references inside slice variable ([#1550](#1550)). * Fixed bundle not loading when empty variable is defined ([#1552](#1552)). * Use `vfs.Path` for filesystem interaction ([#1554](#1554)). * Replace `vfs.Path` with extension-aware filer when running on DBR ([#1556](#1556)). Internal: * merge.Override: Fix handling of dyn.NilValue ([#1530](#1530)). * Compare `.Kind()` instead of direct equality checks on a `dyn.Value` ([#1520](#1520)). * PythonMutator: register product in user agent extra ([#1533](#1533)). * Ignore `dyn.NilValue` when traversing value from `dyn.Map` ([#1547](#1547)). * Add extra tests for the sync block ([#1548](#1548)). * PythonMutator: add diagnostics ([#1531](#1531)). * PythonMutator: support omitempty in PyDABs ([#1513](#1513)). * PythonMutator: allow insert 'resources' and 'resources.jobs' ([#1555](#1555)).
Changes
PyDABs output can omit empty sequences/mappings because we don't track them as optional. There is no semantic difference between empty and missing, which makes omitting correct. CLI detects that we falsely modify input resources by deleting all empty collections.
To handle that, we extend
dyn.Override
to allow visitors to ignore certain deletes. If we see that an empty sequence or mapping is deleted, we revert such delete.Tests
Unit tests