marshmallow icon indicating copy to clipboard operation
marshmallow copied to clipboard

Make context available to callable `missing`

Open lawschlosser opened this issue 3 years ago • 2 comments

Related: https://github.com/marshmallow-code/marshmallow/issues/394. I was hoping to use the context dictionary to drive field logic, but I was disappointed to find that when using the missing parameter as a callable function, there is no avenue for accessing the context data.

I'd like to propose feeding the context dictionary as a parameter to the missing callable (unfortunately this would be a breaking change).

The rationale:

  1. The purpose behind context (if I am not mistaken) is to provide information to drive logic within a Field/Schema's methods.
  2. The purpose behind the missing callable is to support an asynchronous/callback mechanism to allow the missing value to be determined/defined after the field has been instantiated (i.e. during load/parse time).
  3. To support both of the above purposes, I would think it appropriate to provide the context when calling the missing callable.

Below is a somewhat simplified example of what I would like to achieve.

In this specific case I have a custom field where I can define the missing callback on the Field itself, and have the context be provided to it.

class UserId(marshmallow.fields.Str):

    def __init__(self, *args, **kwargs):
        kwargs["missing"] = self._get_missing
        super(UserId, self).__init__(*args, **kwargs)

    @classmethod
    def _get_missing(cls, context):
        return context["user_id"]

Add it to a simple UserSchema... (note that the missing parameter is not specified in the UserId instantiation)

class UserSchema(marshmallow.Schema):
    id = UserId()

And then parse...

import flask
from myapp import authenticate
schema = UserSchema()
schema.context = authenticate()  # injects user information (e.g the user's actual id)
parsed = schema.load({}) # note the empty dictionary, thereby invoking the field's `missing` callable
# parsed {id: "302339403"}  # sweet, the `missing` callback populated the id for us!

Obviously the missing callable does not need to be defined as method on the field, but I figured this implementation might turn some gears for other potential solutions.

I'm a noob to marshmallow, so perhaps there are better ways to skin/think about this. Much appreciated!

And thank your for all of your work!

lawschlosser avatar Dec 01 '20 21:12 lawschlosser

Apologies for the delayed response.

This is similar to #289 . I'm considering if we should add something along the lines of DRF's API for opting into context for validation and default functions: https://www.django-rest-framework.org/community/3.11-announcement/#validator-default-context .

In the meantime, I like the workaround you described.

sloria avatar Apr 04 '21 04:04 sloria

I think the context feature rework proposed in #1826 would solve this.

lafrech avatar Jun 28 '21 08:06 lafrech