-
Notifications
You must be signed in to change notification settings - Fork 53
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
Protobuf api V2: add protoMessage, merge and autoboxing wrapperspb #90
Conversation
2adabf6
to
4089d9c
Compare
9e05611
to
1a154d8
Compare
1a154d8
to
fbffa16
Compare
@@ -1,4 +1,4 @@ | |||
// Copyright 2020 The Skycfg Authors. | |||
// Copyright 2021 The Skycfg Authors. |
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.
😎
fields := make(map[string]starlark.Value) | ||
|
||
// Copy any existing set fields | ||
msgReflect := msg.ProtoReflect() |
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.
nit: Since msg.ProtoReflect()
is also used on line 36, could we move this line to be before line 36 so that line 36 can use this variable?
} | ||
|
||
val, err := valueToStarlark(fieldDesc.Default(), fieldDesc) | ||
if err != nil { |
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.
OOC - would we want to revert the fields for which we've already set defaults? Or is it okay to leave the proto message in a partially updated state where some fields have defaults and others don't (but could)?
Relatedly, is there value in collecting errors (to return at the end of the method) while continuing to set as many default values as possible?
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.
Are you asking if SetDefaults
should behave like first clearing the message like proto.Reset
and then setting the defaults for fields that have them? If so this is what I would expect and that's what the stated behavior in the docs seems to apply https://github.com/stripe/skycfg/blob/trunk/docs/modules.asciidoc#proto.set_defaults but let me look into how the current implementation behaves
With errors, I don't think it really matters as when an error is returned the starlark/skycfg evaluation stops and returns the error. Since Skycfg is not mutating any values outside of the evaluation, all these values will just get thrown away anyway even if in a partial state
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.
Alright I tested the existing implementation and it does not behave this way, only setting values with defaults not clearing those without. It calls out to https://github.com/golang/protobuf/blob/master/proto/defaults.go#L25 and here it's filtering out to only fields with HasDefault()
which AFAICT is only true for fields with proto2 defaults
This deviates from my expectation/Skycfg's state docs but is also what protobuf is doing as well. That said I would prefer to match the existing behavior as closely as possible to de-risk the new implementation refactor, and then change any behavior separately/explicitly afterwards
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.
Sorry for the confusion!
Are you asking if SetDefaults should behave like first clearing the message like proto.Reset and then setting the defaults for fields that have them?
No, I was asking "when SetDefaults
errors, should we clear the errors that were successfully set earlier in SetDefaults
?" i.e. Should setting defaults be all-or-nothing or "best effort"?
But based on
Since Skycfg is not mutating any values outside of the evaluation, all these values will just get thrown away anyway even if in a partial state
it sounds like this is all-or-nothing?
That said I would prefer to match the existing behavior as closely as possible to de-risk the new implementation refactor, and then change any behavior separately/explicitly afterwards
👍 SGTM!
} | ||
|
||
merged, err := mergeField(msg.fields[fieldName], val) | ||
if err != nil { |
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.
same question here about whether it's safe/expected to leave the proto in a partially-merged state
go/protomodule/type_conversions.go
Outdated
} | ||
return nil, fmt.Errorf("ValueError: value %v is not exactly representable as type `int64'.", val) | ||
} | ||
case UInt32ValueType: |
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.
There's already a check for this case on line 253 (similarly for case UInt64ValueType
on line 315 below).
EDIT: This is the only blocking comment.
Summary
This PR adds the remaining type implementation
protoMessage
matches https://github.com/stripe/skycfg/blob/trunk/internal/go/skycfg/proto_message.gomaybeConvertToWrapper
copiesskycfg/internal/go/skycfg/proto_message.go
Line 368 in 3410450
merge
is an implementation ofproto.Merge
Implementation differences
The main implementation differences here is the new implementation does not store values on the underlying proto.Message, which is only used as a type to later instantiate when using
toProtoMessage
. All the values are stored only on thefields
map (which is similar to theattrCache
) from before but the old implementation attempted to keep bothmsg
andattrCache
in sync, producing a lot of extra code and some weird edge case bugs.This means that
NewMessage
will not mutate the incoming proto message. This is mostly an internal detail except when passing in global values into skycfg -- the evaluated starlark will no longer be able to mutate incoming global variables. IMO this is a good thing, as it's surprising behavior, and a user can always fetch the updated value withAsProtoMessage
Example:
In the old implementation,
msg
is directly mutated, sostarlark.Eval
can cause a side effect. This means repeatedly runningeval
can produce different results.In the new implementation,
msg
is unchanged, and the user can use the following to extract the changed global if they wishTests
This is all tested on https://github.com/stripe/skycfg/tree/seena/protobuf-api-v2 but am not adding the tests as part of this PR as they involve making skycfg use
*protoMessage
in place of the legacy*skyProtoMessage
-- this is the switch from old to new implementation, and I thought it would be better to separate that into it's own PR, since again this pr is mostly boilerplate