Skip to content

each_item should iterate only at the top-level instead of going through nested items #1933

@kevlarr

Description

@kevlarr

Output of python -c "import pydantic.utils; print(pydantic.utils.version_info())":

             pydantic version: 1.5.1
            pydantic compiled: True
                 install path: ...snip...
               python version: 3.6.9 (default, Jun 26 2020, 13:24:16)  [GCC 4.2.1 Compatible Apple LLVM 11.0.0 (clang-1100.0.33.16)]
                     platform: Darwin-18.7.0-x86_64-i386-64bit
     optional deps. installed: ['typing-extensions']

I'm seeing what appears to be inconsistent behavior with each_item=True when I'm using a field that's a list of tuples.

For instance, a 'normal' model illustrates what seems to be logical behavior.

from typing import List, Tuple
from pydantic import BaseModel, validator

class Thing(BaseModel):
    things: List[str]

    @validator("things", each_item=False)
    def validate_all_things(cls, val):
        print(f"all vals: {val}")
        return val

    @validator("things", each_item=True)
    def validate_single_thing(cls, val):
        print(f"single val: {val}")
        return val


>>> Thing(things=["one", "two", "three,four"])

single val: one
single val: two
single val: three,four
all vals: ['one', 'two', 'three,four']
Thing(things=['one', 'two', 'three,four'])

But if the field is anything like List[Tuple[str], str]], then behavior is absolutely different.

class Thing2(BaseModel):
    things: List[Tuple[str, str]]

    @validator("things", each_item=False)
    def validate_all_things(cls, val):
        print(f"all vals: {val}")
        return val

    @validator("things", each_item=True)
    def validate_single_thing(cls, val):
        print(f"single val: {val}")
        return val


>>> Thing2(things=[("one", "two"), ("three", "four")])

single val: one
single val: two
single val: three
single val: four
all vals: [('one', 'two'), ('three', 'four')]
Thing2(things=[('one', 'two'), ('three', 'four')])

The output from validate_all_things makes perfect sense - it's just the entire list passed in.

I would expect, however, that each_item would do just what it implies, namely calling the validator on each item of the list no matter what the item is. Instead, it's operating on every value within each tuple within the list, and I cannot get it to perform in a way where val == ("one", "two").

Is this expected behavior? If so, why?

I mean, strings are iterable just like tuples, so why isn't each_item iterating over the characters of each string in the first case?

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug V1Bug related to Pydantic V1.X

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions