Repository: pydantic/pydantic

Issue:
`each_item` should iterate only at the top-level instead of going through nested items
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.

```py
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.

```py
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?


Comments:
Hello @kataev 
I agree the behaviour is not the expected one and for me this is a bug.

Patch:
diff --git a/pydantic/fields.py b/pydantic/fields.py
--- a/pydantic/fields.py
+++ b/pydantic/fields.py
@@ -518,10 +518,26 @@ def _type_analysis(self) -> None:  # noqa: C901 (ignore complexity)
         self.sub_fields = [self._create_sub_type(self.type_, '_' + self.name)]
 
     def _create_sub_type(self, type_: Type[Any], name: str, *, for_keys: bool = False) -> 'ModelField':
+        if for_keys:
+            class_validators = None
+        else:
+            # validators for sub items should not have `each_item` as we want to check only the first sublevel
+            class_validators = {
+                k: Validator(
+                    func=v.func,
+                    pre=v.pre,
+                    each_item=False,
+                    always=v.always,
+                    check_fields=v.check_fields,
+                    skip_on_failure=v.skip_on_failure,
+                )
+                for k, v in self.class_validators.items()
+                if v.each_item
+            }
         return self.__class__(
             type_=type_,
             name=name,
-            class_validators=None if for_keys else {k: v for k, v in self.class_validators.items() if v.each_item},
+            class_validators=class_validators,
             model_config=self.model_config,
         )
 


Test patch:
diff --git a/tests/test_validators.py b/tests/test_validators.py
--- a/tests/test_validators.py
+++ b/tests/test_validators.py
@@ -575,6 +575,19 @@ def check_foobar(cls, v):
     assert Model(foobar={1: 1}).foobar == {1: 2}
 
 
+def test_validation_each_item_one_sublevel():
+    class Model(BaseModel):
+        foobar: List[Tuple[int, int]]
+
+        @validator('foobar', each_item=True)
+        def check_foobar(cls, v: Tuple[int, int]) -> Tuple[int, int]:
+            v1, v2 = v
+            assert v1 == v2
+            return v
+
+    assert Model(foobar=[(1, 1), (2, 2)]).foobar == [(1, 1), (2, 2)]
+
+
 def test_key_validation():
     class Model(BaseModel):
         foobar: Dict[int, int]