Add unset field semantics for structs ("strict structs")
Cleanup and a few fixes to https://github.com/Point72/csp/pull/574, thanks @sim15 for the contribution!
Previously, when all fields on structs were optional, we hard-coded these two flags for pydantic validation
- https://github.com/Point72/csp/blob/strict-structs/csp/impl/struct.py#L125
- https://github.com/Point72/csp/blob/strict-structs/csp/impl/struct.py#L130
Can we only apply this logic when allow_unset=True?
I think that when allow_unset is False, pydantic should infer it correctly based on the declared type and the default value, though we should add a unit test.
Previously, when all fields on structs were optional, we hard-coded these two flags for pydantic validation
- https://github.com/Point72/csp/blob/strict-structs/csp/impl/struct.py#L125
- https://github.com/Point72/csp/blob/strict-structs/csp/impl/struct.py#L130
Can we only apply this logic when
allow_unset=True? I think that whenallow_unsetis False, pydantic should infer it correctly based on the declared type and the default value, though we should add a unit test.
I tested out this approach and it doesn't validate correctly in the case of a required field with a default value.
class MyStrictStruct(csp.Struct, allow_unset=False):
req_default_str: str = "default"
E pydantic_core._pydantic_core.SchemaError: Error building "list" validator:
E SchemaError: Error building "function-wrap" validator:
E SchemaError: Error building "typed-dict" validator:
E SchemaError: Field 'req_default_str': a required field cannot have a default value
Previously, when all fields on structs were optional, we hard-coded these two flags for pydantic validation
- https://github.com/Point72/csp/blob/strict-structs/csp/impl/struct.py#L125
- https://github.com/Point72/csp/blob/strict-structs/csp/impl/struct.py#L130
Can we only apply this logic when
allow_unset=True? I think that whenallow_unsetis False, pydantic should infer it correctly based on the declared type and the default value, though we should add a unit test.I tested out this approach and it doesn't validate correctly in the case of a required field with a default value.
class MyStrictStruct(csp.Struct, allow_unset=False): req_default_str: str = "default"E pydantic_core._pydantic_core.SchemaError: Error building "list" validator: E SchemaError: Error building "function-wrap" validator: E SchemaError: Error building "typed-dict" validator: E SchemaError: Field 'req_default_str': a required field cannot have a default value
I think this just means that if there is a default value, we leave it as "optional" (as the user doesn't have to provide it), but if there isn't, then it's not. I guess I was wrong about pydantic inferring it. However, the behavior for non-defaulted fields will be different for the two types of Struct.