-
Notifications
You must be signed in to change notification settings - Fork 694
reject file path input defaults #3094
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -361,6 +361,66 @@ class Predictor(BasePredictor): | |
| require.False(t, scale.IsRequired()) | ||
| } | ||
|
|
||
| func TestPathAndFileInputsRejectDefaults(t *testing.T) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we add one regression test for the static-method/reference path too? The new table is good for direct A useful test would be the non-file helper-method case from the other comment: helper returns It would also be worth adding one Path/File case through this path, e.g. |
||
| tests := []struct { | ||
| name string | ||
| source string | ||
| wantErr schema.SchemaErrorKind | ||
| }{ | ||
| { | ||
| name: "path string default", | ||
| source: ` | ||
| from cog import BasePredictor, Input, Path | ||
|
|
||
| class Predictor(BasePredictor): | ||
| def predict(self, image: Path = Input(default="image.png")) -> str: | ||
| return "ok" | ||
| `, | ||
| wantErr: schema.ErrUnsupportedType, | ||
| }, | ||
| { | ||
| name: "file string default", | ||
| source: ` | ||
| from cog import BasePredictor, File, Input | ||
|
|
||
| class Predictor(BasePredictor): | ||
| def predict(self, image: File = Input(default="image.png")) -> str: | ||
| return "ok" | ||
| `, | ||
| wantErr: schema.ErrUnsupportedType, | ||
| }, | ||
| { | ||
| name: "path constructor default", | ||
| source: ` | ||
| from cog import BasePredictor, Input, Path | ||
|
|
||
| class Predictor(BasePredictor): | ||
| def predict(self, image: Path = Input(default=Path("image.png"))) -> str: | ||
| return "ok" | ||
| `, | ||
| wantErr: schema.ErrDefaultNotResolvable, | ||
| }, | ||
| { | ||
| name: "path list default", | ||
| source: ` | ||
| from cog import BasePredictor, Input, Path | ||
|
|
||
| class Predictor(BasePredictor): | ||
| def predict(self, images: list[Path] = Input(default=["image.png"])) -> str: | ||
| return "ok" | ||
| `, | ||
| wantErr: schema.ErrUnsupportedType, | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| se := parseErr(t, tt.source, "Predictor", schema.ModePredict) | ||
| require.Equal(t, tt.wantErr, se.Kind) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Small optional tightening: these assertions would be a little stronger if the table also checked a message substring. The
Not a blocker, just a cheap way to make the regression tests more explicit. |
||
| }) | ||
| } | ||
| } | ||
|
|
||
| // --------------------------------------------------------------------------- | ||
| // Optional / union inputs | ||
| // --------------------------------------------------------------------------- | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -245,9 +245,38 @@ func ValidateInputField(field InputField) error { | |
| return errUnsupportedType("constraints and choices are not supported on union inputs") | ||
| } | ||
| } | ||
| if inputFieldContainsFileOrPath(field) && field.Default != nil && field.Default.Kind != DefaultNone { | ||
| return errUnsupportedType("defaults are not supported on Path or File inputs") | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // InputTypeContainsFileOrPath reports whether a recursive input type contains | ||
| // a Path or File primitive. It is used by parser frontends that need to reject | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tiny doc nit: this helper is also used by Maybe: // It is used by ValidateInputField and parser frontends that need to reject
// unsupported file/path defaults after annotation resolution.Optional, but it would make the comment match the actual call sites. |
||
| // unsupported file/path defaults after annotation resolution. | ||
| func InputTypeContainsFileOrPath(inputType InputType) bool { | ||
| switch inputType.Kind { | ||
| case InputKindPrimitive: | ||
| return inputType.Primitive == TypePath || inputType.Primitive == TypeFile | ||
| case InputKindArray: | ||
| return inputType.Elem != nil && InputTypeContainsFileOrPath(*inputType.Elem) | ||
| case InputKindUnion: | ||
| for _, variant := range inputType.Variants { | ||
| if InputTypeContainsFileOrPath(variant) { | ||
| return true | ||
| } | ||
| } | ||
| } | ||
| return false | ||
| } | ||
|
|
||
| func inputFieldContainsFileOrPath(field InputField) bool { | ||
| if field.InputType != nil { | ||
| return InputTypeContainsFileOrPath(*field.InputType) | ||
| } | ||
| return field.FieldType.Primitive == TypePath || field.FieldType.Primitive == TypeFile | ||
| } | ||
|
|
||
| // PredictorInfo is the top-level extraction result. | ||
| type PredictorInfo struct { | ||
| Inputs *OrderedMap[string, InputField] | ||
|
|
||
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.
Nice catch overall. I think this branch needs one small fix here before it lands: this
elsechanges behavior outside the Path/File case.resolvedstarts as a copy ofmethodInfo.BaseInfo, so it can already have a default from the helper method. Before this PR, if a call-site default was not a literal, we left that base default alone. Now we replace it withNone.I verified this with a non-file input like:
On this branch the parsed default becomes
None; before the PR it stayed"base.png". That is a silent schema change for non-file inputs.Could we keep the new unresolved marker without clobbering the base default?
I checked this locally: it preserves the old non-file behavior, and file/path defaults through this path still get rejected because
validateInputFieldWithInfoseesDefaultUnresolved.