Home > Blockchain >  Pydantic: 'NoneType' object is not subscriptable (type=type_error)
Pydantic: 'NoneType' object is not subscriptable (type=type_error)

Time:09-15

I have the following structure of the models using Pydantic library. I created some of the classes, and one of them contains list of items of another, so the problem is that I can't parse json using this classes:

class FileTypeEnum(str, Enum):
file = 'FILE'
folder = 'FOLDER'


class ImportInModel(BaseModel):
    id: constr(min_length=1)
    url: constr(max_length=255) = None
    parentId: str | None = None
    size: PositiveInt | None = None
    type: FileTypeEnum

    @root_validator
    def check_url(cls, values: dict):
        file_type = values['type']
        file_url = values['url']
        if file_type == FileTypeEnum.folder and file_url is not None:
            raise ValueError(
                f'{file_type}\'s type file has {file_url} file url!'
            )


    @root_validator
    def check_size(cls, values: dict):
        file_type = values['type']
        file_size = values['size']
        if file_type == FileTypeEnum.file and file_size is None:
            raise ValueError(
                f'{file_type}\'s type file has {file_size} file size!'
            )


class ImportsInModel(BaseModel):
    items: list[ImportInModel]
    updateDate: datetime

    class Config:
        json_encoders = {
            datetime: isoformat
        }
        json_loads = ujson.loads


    @validator('items')
    def check_parent(cls, v):
        for item_1 in v:
            for item_2 in v:
                print(item_1.type, item_1.parentId, item_2.id, item_2.type)
                assert item_1.type == FileTypeEnum.file \
                        and item_1.parentId == item_2.id  \
                        and item_2.type == FileTypeEnum.folder

But then I use it like

try:
    json_raw = '''{
        "items": [
            {
            "id": "элемент_1_4",
            "url": "/file/url1",
            "parentId": "элемент_1_1",
            "size": 234,
            "type": "FILE"
            }
        ],
        "updateDate": "2022-05-28T21:12:01.000Z"
        }
    '''
    ImportsInModel.parse_raw(json_raw)
    # print(json_)
except ValidationError as e:
    print(e)

It gives me error:

1 validation error for ImportsInModel items -> 0 -> __root__
'NoneType' object is not subscriptable (type=type_error)

And I have no idea what's wrong, because it literally copy of the documentation.

CodePudding user response:

You have to return parsed result after validation if success, i.e., you should add return values in the end of the two root_validator in ImportInModel.

For instance, if I run below code, a corresponding error will throw up:

if __name__ == '__main__':
    try:
        x_raw = ''' 
       {     
            "id": "элемент_1_4",
            "url": "/file/url1",
            "parentId": "элемент_1_1",
            "size": 234,
            "type": "FILE"
        } 
        
        '''
        y = ImportInModel.parse_raw(x_raw)
    except ValidationError as e:
        print(e)

Traceback (most recent call last):
  File "pydantic/main.py", line 344, in pydantic.main.BaseModel.__init__
TypeError: __dict__ must be set to a dictionary, not a 'NoneType'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/will/PycharmProjects/pythonProject2/pydantic_1.py", line 90, in <module>
    y = ImportInModel.parse_raw(x_raw)
  File "pydantic/main.py", line 549, in pydantic.main.BaseModel.parse_raw
  File "pydantic/main.py", line 526, in pydantic.main.BaseModel.parse_obj
  File "pydantic/main.py", line 346, in pydantic.main.BaseModel.__init__
TypeError: Model values must be a dict; you may not have returned a dictionary from a root validator

As for the validator in ImportsInModel, maybe you should check your logic of the code. You codes want to assert item_1.parentId == item_2.id. However, in your testcase, item_1.parentId will never equal to item_2.id since you only have one item in your items list, which means item_1 == item_2.

So the final snippet is:

from datetime import datetime
from enum import Enum

import ujson
from pydantic.json import isoformat
from pydantic import BaseModel, constr, PositiveInt, root_validator, validator, ValidationError


class FileTypeEnum(Enum):
    file = 'FILE'
    folder = 'FOLDER'


class ImportInModel(BaseModel):
    id: constr(min_length=1)
    url: constr(max_length=255) = None
    parentId: str | None = None
    size: PositiveInt | None = None
    type: FileTypeEnum

    @root_validator
    def check_url(cls, values: dict):
        file_type = values['type']
        file_url = values['url']
        if file_type == FileTypeEnum.folder and file_url is not None:
            raise ValueError(
                f'{file_type}\'s type file has {file_url} file url!'
            )
        return values

    @root_validator
    def check_size(cls, values: dict):
        file_type = values['type']
        file_size = values['size']
        if file_type == FileTypeEnum.file and file_size is None:
            raise ValueError(
                f'{file_type}\'s type file has {file_size} file size!'
            )
        return values


class ImportsInModel(BaseModel):
    items: list[ImportInModel]
    updateDate: datetime

    class Config:
        json_encoders = {
            datetime: isoformat
        }
        json_loads = ujson.loads

    @validator('items')
    def check_parent(cls, v):
        for item_1 in v:
            for item_2 in v:
                print(item_1.type, item_1.parentId, item_2.id, item_2.type)
                assert item_1.type == FileTypeEnum.file \
                       and item_1.parentId == item_2.id \
                       and item_2.type == FileTypeEnum.folder


if __name__ == '__main__':
    try:
        json_raw = '''{
        "items": [
            {
            "id": "элемент_1_4",
            "url": "/file/url1",
            "parentId": "элемент_1_1",
            "size": 234,
            "type": "FILE"
            }
        ],
        "updateDate": "2022-05-28T21:12:01.000Z"
        }
    '''
        x_raw = ''' 
       {     
            "id": "элемент_1_4",
            "url": "/file/url1",
            "parentId": "элемент_1_1",
            "size": 234,
            "type": "FILE"
        } 
        
        '''
        y = ImportInModel.parse_raw(x_raw)
        z = ImportsInModel.parse_raw(json_raw)
        print(y, z)
    except ValidationError as e:
        print(e)
  • Related