In "strict" parameter mode, class parameterization change behavior in the following ways:
serialized_params use the new cbor2-based serialization format (see #1966 )
We set class_parameter_format=PARAM_SERIALIZATION_FORMAT_CBOR2_MAP on the Function definition to indicate the serialization protocol to be used
We set class_parameters (see proto for format) on the Function definition defining the schema of the parameters of the class (names and types for now)
Reasoning behind class_parameters:
We could (and are basically doing that, at this stage) just use cbor2 directly on the parameter kwargs, similar to how we use pickle today and never store any schema, and things would generally work well, with the added benefit of supporting all cbor2 native types as parameter values.
However, the stored class_parameters schema is useful/necessary for three main reasons:
Web endpoint parameterization will need yet another (de)serialization format - one that goes from query parameters to a cbor native representation. Since query parameters are untyped strings, we'd need some kind of type information to support typed arguments with web endpoint parameterization.
We can potentially use the schema to hydrate class instances in the client in a way that lets us error out sooner in case of bad arguments to a class constructor (wrong arguments, types etc.). Today these sort of errors don't appear until the launched container starts up and the constructor is actually called (could be considered both bug and feature...)
It lets us add additional types that aren't natively supported by cbor2. For example we could have a PARAM_TYPE_PYTHON_OBJ (which would only be supported by Python clients) that pickles the specified field into a bytes field of the cbor2 "data transfer object".
Feature flag
This new feature is currently gated behind the MODAL_STRICT_PARAMETERS=1 env var and uses the existing class constructor logic but with signature inspection.
When we actually release this to users (when the backend support for web parameterization is live) an idea is to instead activate strict parameters when users use a new kind of dataclass-inspired schema (which has other benefits!), and keep the unstrict behavior of custom constructors, to not break any existing user code.
Note that this is not part of this PR, just an example of how we'd introduce this in a non-breaking way:
@app.cls()
class Foo:
a: int [= parameter(default=123)] #
b: int = field(init=False) # non-parameter annotation, stuff that's set in @enter methods etc.
The above syntax would let us use typing.dataclass_transform() to get good editor support for our classes even without explicit constructors 🤓
In "strict" parameter mode, class parameterization change behavior in the following ways:
serialized_params
use the new cbor2-based serialization format (see #1966 )class_parameter_format=PARAM_SERIALIZATION_FORMAT_CBOR2_MAP
on theFunction
definition to indicate the serialization protocol to be usedclass_parameters
(see proto for format) on theFunction
definition defining the schema of the parameters of the class (names and types for now)Reasoning behind
class_parameters
:We could (and are basically doing that, at this stage) just use cbor2 directly on the parameter kwargs, similar to how we use pickle today and never store any schema, and things would generally work well, with the added benefit of supporting all cbor2 native types as parameter values.
However, the stored
class_parameters
schema is useful/necessary for three main reasons:PARAM_TYPE_PYTHON_OBJ
(which would only be supported by Python clients) that pickles the specified field into a bytes field of the cbor2 "data transfer object".Feature flag
This new feature is currently gated behind the
MODAL_STRICT_PARAMETERS=1
env var and uses the existing class constructor logic but with signature inspection.When we actually release this to users (when the backend support for web parameterization is live) an idea is to instead activate strict parameters when users use a new kind of dataclass-inspired schema (which has other benefits!), and keep the unstrict behavior of custom constructors, to not break any existing user code.
Note that this is not part of this PR, just an example of how we'd introduce this in a non-breaking way:
The above syntax would let us use
typing.dataclass_transform()
to get good editor support for our classes even without explicit constructors 🤓