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

[Flyte][3][flytepropeller][Attribute Access][flytectl] Binary IDL With MessagePack #5763

Merged
merged 11 commits into from
Oct 5, 2024
97 changes: 89 additions & 8 deletions flytepropeller/pkg/controller/nodes/attr_path_resolver.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package nodes

import (
"github.com/shamaton/msgpack/v2"
"google.golang.org/protobuf/types/known/structpb"

"github.com/flyteorg/flyte/flyteidl/gen/pb-go/flyteidl/core"
Expand Down Expand Up @@ -37,13 +38,20 @@
}
}

// resolve dataclass
if currVal.GetScalar() != nil && currVal.GetScalar().GetGeneric() != nil {
st := currVal.GetScalar().GetGeneric()
// start from index "count"
currVal, err = resolveAttrPathInPbStruct(nodeID, st, bindAttrPath[count:])
if err != nil {
return nil, err
// resolve dataclass and Pydantic BaseModel
if scalar := currVal.GetScalar(); scalar != nil {
if binary := scalar.GetBinary(); binary != nil {
// Start from index "count"
currVal, err = resolveAttrPathInBinary(nodeID, binary, bindAttrPath[count:])
if err != nil {
return nil, err
}
} else if generic := scalar.GetGeneric(); generic != nil {
// Start from index "count"
pingsutw marked this conversation as resolved.
Show resolved Hide resolved
currVal, err = resolveAttrPathInPbStruct(nodeID, generic, bindAttrPath[count:])
if err != nil {
return nil, err
}
}
}

Expand Down Expand Up @@ -84,6 +92,79 @@
return literal, err
}

// resolveAttrPathInBinary resolves the binary idl object (e.g. dataclass, pydantic basemodel) with attribute path
func resolveAttrPathInBinary(nodeID string, binaryIDL *core.Binary, bindAttrPath []*core.PromiseAttribute) (*core.
Literal,
error) {

binaryBytes := binaryIDL.GetValue()
serializationFormat := binaryIDL.GetTag()

var currVal interface{}
var tmpVal interface{}
var exist bool

if serializationFormat == "msgpack" {
pingsutw marked this conversation as resolved.
Show resolved Hide resolved
err := msgpack.Unmarshal(binaryBytes, &currVal)
if err != nil {
return nil, err

Check warning on line 110 in flytepropeller/pkg/controller/nodes/attr_path_resolver.go

View check run for this annotation

Codecov / codecov/patch

flytepropeller/pkg/controller/nodes/attr_path_resolver.go#L110

Added line #L110 was not covered by tests

}
} else {
return nil, errors.Errorf(errors.PromiseAttributeResolveError, nodeID,
"Unsupported format '%v' found for literal value.\n"+
"Please ensure the serialization format is supported.", serializationFormat)

Check warning on line 116 in flytepropeller/pkg/controller/nodes/attr_path_resolver.go

View check run for this annotation

Codecov / codecov/patch

flytepropeller/pkg/controller/nodes/attr_path_resolver.go#L113-L116

Added lines #L113 - L116 were not covered by tests
}

// Turn the current value to a map, so it can be resolved more easily
for _, attr := range bindAttrPath {
switch resolvedVal := currVal.(type) {
// map
case map[interface{}]interface{}:
Future-Outlier marked this conversation as resolved.
Show resolved Hide resolved
tmpVal, exist = resolvedVal[attr.GetStringValue()]
Copy link
Contributor

Choose a reason for hiding this comment

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

What will GetStringValue() return if if the attr is foo[0]? shouldn't it fail in that case and say "you can't index into a struct" or something ?

Copy link
Member Author

Choose a reason for hiding this comment

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

if !exist {
return nil, errors.Errorf(errors.PromiseAttributeResolveError, nodeID, "key [%v] does not exist in literal %v", attr.GetStringValue(), currVal)
}
currVal = tmpVal
// list
case []interface{}:
if int(attr.GetIntValue()) >= len(resolvedVal) {
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto here. If it's foo.bar GetIntValue() will return 0 I presume? it should fail here too

Copy link
Member Author

Choose a reason for hiding this comment

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

yes, GetIntValue() will return 0 , but foo.bar will go to the up map case, so it will called attr.GetStringValue to get the bar attribute

return nil, errors.Errorf(errors.PromiseAttributeResolveError, nodeID, "index [%v] is out of range of %v", attr.GetIntValue(), currVal)
}
currVal = resolvedVal[attr.GetIntValue()]
}
}

if serializationFormat == "msgpack" {
// Marshal the current value to MessagePack bytes
resolvedBinaryBytes, err := msgpack.Marshal(currVal)
if err != nil {
return nil, err

Check warning on line 142 in flytepropeller/pkg/controller/nodes/attr_path_resolver.go

View check run for this annotation

Codecov / codecov/patch

flytepropeller/pkg/controller/nodes/attr_path_resolver.go#L142

Added line #L142 was not covered by tests
}
// Construct and return the binary-encoded literal
return constructResolvedBinary(resolvedBinaryBytes, serializationFormat), nil
}
// Unsupported serialization format
return nil, errors.Errorf(errors.PromiseAttributeResolveError, nodeID,
"Unsupported format '%v' found for literal value.\n"+
"Please ensure the serialization format is supported.", serializationFormat)

Check warning on line 150 in flytepropeller/pkg/controller/nodes/attr_path_resolver.go

View check run for this annotation

Codecov / codecov/patch

flytepropeller/pkg/controller/nodes/attr_path_resolver.go#L148-L150

Added lines #L148 - L150 were not covered by tests
Copy link
Contributor

Choose a reason for hiding this comment

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

This case can never happen, right? since you checked for that early on

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I can remove it

}

func constructResolvedBinary(resolvedBinaryBytes []byte, serializationFormat string) *core.Literal {
return &core.Literal{
Value: &core.Literal_Scalar{
Scalar: &core.Scalar{
Value: &core.Scalar_Binary{
Binary: &core.Binary{
Value: resolvedBinaryBytes,
Tag: serializationFormat,
},
},
},
},
}
}

// convertInterfaceToLiteral converts the protobuf struct (e.g. dataclass) to literal
func convertInterfaceToLiteral(nodeID string, obj interface{}) (*core.Literal, error) {

Expand Down Expand Up @@ -128,7 +209,7 @@
return literal, nil
}

// convertInterfaceToLiteralScalar converts the a single value to a literal scalar
// convertInterfaceToLiteralScalar converts a single value to a literal scalar
func convertInterfaceToLiteralScalar(nodeID string, obj interface{}) (*core.Literal_Scalar, error) {
value := &core.Primitive{}

Expand Down
Loading
Loading