modal-labs / modal-client

Python client library for Modal
https://modal.com/docs
Apache License 2.0
271 stars 35 forks source link

Strict class parameters - proto edition #1970

Closed freider closed 2 months ago

freider commented 3 months ago

Alternative implementation of #1968 using a simple proto schema instead of cbor2 to encode the parameters.

As long as we are confident the encoded payload will be deterministic, this would be a pretty clean solution IMO as it enforces types harder in the serialization layer than cbor2.


Updated PR description from #1968

In "strict" parameter mode, class parameterization change behavior in the following ways:

Reasoning behind class_parameter_schema:

The stored class_parameter_schema is useful/necessary for three main reasons:

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 🤓

freider commented 3 months ago

One thing I don't fully understand — what's "strict" about the params here? That they need to have type annotations in the modal class constructor?

Strict as in strictly typed in some sense, and that they (for now) only allow int and str types.

A somewhat unintended (positive) side effect of this mode is that it enforces the right arguments and types are supplied already at the call site, avoiding launch of containers with invalid params. The old "mode" just happily let you instantiate the class with whatever *args, **kwargs you wanted and it wouldn't actually explode until your already newly launched container tried to supply those to the underlying class.

mwaskom commented 3 months ago

A somewhat unintended (positive) side effect of this mode is that it enforces the right arguments and types are supplied already at the call site, avoiding launch of containers with invalid params.

Yeah that's a plus!