Pydantic: Allow dict like types to __root__

Created on 17 Oct 2019  路  9Comments  路  Source: samuelcolvin/pydantic

Hi @samuelcolvin , Thank you for this amazing library. I am using it with fastapi for defining input models.

"preview": {
        "9:16": {
            "thumbnail": "",
            "video": ""
        }, "16:9": {
            "thumbnail": "",
            "video": ""
        }, "1:1": {
            "thumbnail": "",
            "video": ""
        }
    }

I have the above data coming in the request for which I want to create a model. I tried implementing wildcard fields but didn't get any success. In the above case, the aspect ratio is dynamic and can be anything but will always be in : format. In case that is coming, thumbnail and video are in nested model.

I have implemented this in JSON schema like the following:
template_schema = { "type": "object", "properties": { "preview": { "minProperties": 1, "type": "object", "patternProperties": { "^[0-9]{1,2}:\d{1,2}$": { "type": "object", "properties": { "thumbnail": {"type": "string"}, "video": {"type": "string"} }, "required": ["thumbnail", "video"], } }, }, } }

Please guide me on how to get it to work?

Any leads would be appreciated. Thanks in advance!

feature request

All 9 comments

If you want change the input data to confirm to a more conventional shape, you'd be best of with something like:

class ChildModel(BaseModel):
    thumbnail: str
    video: str

class MainModel(BaseModel):
    __root__: Dict[str, ChildModel]

Then you'll need a validator to check the format of the keys.

You'll then need to manually customise the schema

Hi @samuelcolvin, thank you for reverting back so quick. I tried to follow the link and the example shared you above. but wasn't able to achieve the use case as mentioned above. Can you please help me with this? A code example will be a great help.

I get the following error using your code snippet
TypeError: custom root type cannot allow mapping

Thanks in advance!

Bump!

Sorry, I forgot dictionaries can't be used as the root type.

You need to use a key for the dictionaries of video formats, in your above example that's fine since you have {"preview: {...}}.

With that you might want something like:

from typing import Dict
from pydantic import BaseModel, validator
from devtools import debug

class ChildModel(BaseModel):
    thumbnail: str
    video: str

class MainModel(BaseModel):
    preview: Dict[str, ChildModel]

    @validator('preview')
    def check_keys(cls, v):
        for i, k in enumerate(v):
            if ':' not in k:
                raise ValueError(f'{i} key {k!r} does not contain a colon (:)')
        return v


data = {
    'preview': {
        '9:16': {'thumbnail': '', 'video': ''},
        '16:9': {'thumbnail': '', 'video': ''},
        '1:1': {'thumbnail': '', 'video': ''},
        'bad': {'thumbnail': '', 'video': ''},
    }
}
m = MainModel(**data)
debug(m)

Will raise an error as one of the keys doesn't contain a colon.

If you're data is just a dictionary of the form {"9:16": {}, "16:9": {}, ...}, you would need to initialise with something like MainModel(preview=data).

@samuelcolvin Is there a fundamental reason we don't support root mappings, or is it just because this way was easier to implement for now? I recognize it may require adding an unacceptable amount of added complexity to support a mapping type in the root; I'm just trying to understand whether this restriction is more purposeful or accidental.

I think the problem is parse_obj:

https://github.com/samuelcolvin/pydantic/blob/f5cde39e7550871e6ca1aceb70891a4bf9f01608/pydantic/main.py#L356

Might be possible to fix, but that was why we did it.

Yeah, I think it could make sense to replace that with a root model check; it feels kind of arbitrarily limiting to not support mappings as the root model.

On the other hand, I don't love adding all of these runtime checks when in most cases they aren't relevant; maybe there is a way to essentially decorate/replace this method inside the metaclass to get different behavior (if the model is a custom root model with a mapping type)?

(I guess maybe this is starting to get outside the scope of this issue though.)

Hello there,

i'm quite interested in this feature too. I'm getting a payload I don't control the schema. The payload is an object where the keys are all unknown (and of a various format). I wanted to use a mapping as a root type but not sure how to go about it until this has a chance to be reviewed/merged/released.

Cheers

Thanks for your interest, see the discussion on #958 as it happens I'm reviewing the last comment right now and working out what to do.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DrPyser picture DrPyser  路  19Comments

jasonkuhrt picture jasonkuhrt  路  19Comments

sm-Fifteen picture sm-Fifteen  路  45Comments

chopraaa picture chopraaa  路  18Comments

dmfigol picture dmfigol  路  38Comments