Repository: samuelcolvin/pydantic (python)

Issue:
underscore_attrs_are_private and validate_all not compatible with validate_arguments
Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:
```
             pydantic version: 1.8.2
            pydantic compiled: True
                 install path: /home/xxx/.conda/envs/py38/lib/python3.8/site-packages/pydantic
               python version: 3.8.5 (default, Sep  4 2020, 07:30:14)  [GCC 7.3.0]
                     platform: Linux-4.18.0-80.el8.x86_64-x86_64-with-glibc2.10
     optional deps. installed: ['typing-extensions']
```
`underscore_attrs_are_private` not work with `validate_arguments` just like it not work with `create_model`  #3134 .

When I define a function decorated by `validate_arguments` with `validate_all` been set `True`, It will raise `ValidationError`:

```py
from datetime import datetime
from pydantic import validate_arguments, Field


@validate_arguments(config={'validate_all': True})
def foo(dt: datetime = Field(default_factory=lambda : 42)):
    print(type(dt))

foo()
```
```
---------------------------------------------------------------------------
ValidationError                           Traceback (most recent call last)
<ipython-input-4-6c97ede6fd47> in <module>
      7     print(type(dt))
      8 
----> 9 foo()

~/.conda/envs/py38/lib/python3.8/site-packages/pydantic/decorator.cpython-38-x86_64-linux-gnu.so in pydantic.decorator.validate_arguments.validate.wrapper_function()

~/.conda/envs/py38/lib/python3.8/site-packages/pydantic/decorator.cpython-38-x86_64-linux-gnu.so in pydantic.decorator.ValidatedFunction.call()

~/.conda/envs/py38/lib/python3.8/site-packages/pydantic/decorator.cpython-38-x86_64-linux-gnu.so in pydantic.decorator.ValidatedFunction.init_model_instance()

~/.conda/envs/py38/lib/python3.8/site-packages/pydantic/main.cpython-38-x86_64-linux-gnu.so in pydantic.main.BaseModel.__init__()

ValidationError: 3 validation errors for Foo
v__duplicate_kwargs
  object of type 'NoneType' has no len() (type=type_error)
args
  object of type 'NoneType' has no len() (type=type_error)
kwargs
  object of type 'NoneType' has no len() (type=type_error)
```


Pull request description:
fix: make `validate_arguments` work with `Config.validate_all`
<!-- Thank you for your contribution! -->
<!-- Unless your change is trivial, please create an issue to discuss the change before creating a PR -->
<!-- See https://pydantic-docs.helpmanual.io/contributing/ for help on Contributing -->

## Change Summary

<!-- Please give a short summary of the changes. -->

## Related issue number
fix #3135

<!-- Are there any issues opened that will be resolved by merging this change? -->

## Checklist

* [x] Unit tests for the changes exist
* [x] Tests pass on CI and coverage remains at 100%
* [x] Documentation reflects the changes where applicable
* [x] `changes/<pull request or issue id>-<github username>.md` file added describing change
  (see [changes/README.md](https://github.com/samuelcolvin/pydantic/blob/master/changes/README.md) for details)
* [ ] My PR is ready to review, **please add a comment including the phrase "please review" to assign reviewers**


Patch:
diff --git a/changes/3135-PrettyWood.md b/changes/3135-PrettyWood.md
new file mode 100644
index 000000000..643e1f550
--- /dev/null
+++ b/changes/3135-PrettyWood.md
@@ -0,0 +1,1 @@
+fix `validate_arguments` issue with `Config.validate_all`
diff --git a/pydantic/decorator.py b/pydantic/decorator.py
index 869afee10..ca709b405 100644
--- a/pydantic/decorator.py
+++ b/pydantic/decorator.py
@@ -220,15 +220,15 @@ class ValidatedFunction:
 
         class DecoratorBaseModel(BaseModel):
             @validator(self.v_args_name, check_fields=False, allow_reuse=True)
-            def check_args(cls, v: List[Any]) -> List[Any]:
-                if takes_args:
+            def check_args(cls, v: Optional[List[Any]]) -> Optional[List[Any]]:
+                if takes_args or v is None:
                     return v
 
                 raise TypeError(f'{pos_args} positional arguments expected but {pos_args + len(v)} given')
 
             @validator(self.v_kwargs_name, check_fields=False, allow_reuse=True)
-            def check_kwargs(cls, v: Dict[str, Any]) -> Dict[str, Any]:
-                if takes_kwargs:
+            def check_kwargs(cls, v: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
+                if takes_kwargs or v is None:
                     return v
 
                 plural = '' if len(v) == 1 else 's'
@@ -236,13 +236,19 @@ class ValidatedFunction:
                 raise TypeError(f'unexpected keyword argument{plural}: {keys}')
 
             @validator(V_POSITIONAL_ONLY_NAME, check_fields=False, allow_reuse=True)
-            def check_positional_only(cls, v: List[str]) -> None:
+            def check_positional_only(cls, v: Optional[List[str]]) -> None:
+                if v is None:
+                    return
+
                 plural = '' if len(v) == 1 else 's'
                 keys = ', '.join(map(repr, v))
                 raise TypeError(f'positional-only argument{plural} passed as keyword argument{plural}: {keys}')
 
             @validator(V_DUPLICATE_KWARGS, check_fields=False, allow_reuse=True)
-            def check_duplicate_kwargs(cls, v: List[str]) -> None:
+            def check_duplicate_kwargs(cls, v: Optional[List[str]]) -> None:
+                if v is None:
+                    return
+
                 plural = '' if len(v) == 1 else 's'
                 keys = ', '.join(map(repr, v))
                 raise TypeError(f'multiple values for argument{plural}: {keys}')


Test patch:
diff --git a/tests/test_decorator.py b/tests/test_decorator.py
index cbfc2dd55..ea06368b3 100644
--- a/tests/test_decorator.py
+++ b/tests/test_decorator.py
@@ -1,6 +1,7 @@
 import asyncio
 import inspect
 import sys
+from datetime import datetime, timezone
 from pathlib import Path
 from typing import List
 
@@ -399,3 +400,30 @@ def test_validate(mocker):
         func.validate(['qwe'], 2)
 
     stub.assert_not_called()
+
+
+def test_validate_all():
+    @validate_arguments(config=dict(validate_all=True))
+    def foo(dt: datetime = Field(default_factory=lambda: 946684800)):
+        return dt
+
+    assert foo() == datetime(2000, 1, 1, tzinfo=timezone.utc)
+    assert foo(0) == datetime(1970, 1, 1, tzinfo=timezone.utc)
+
+
+@skip_pre_38
+def test_validate_all_positional(create_module):
+    module = create_module(
+        # language=Python
+        """
+from datetime import datetime
+
+from pydantic import Field, validate_arguments
+
+@validate_arguments(config=dict(validate_all=True))
+def foo(dt: datetime = Field(default_factory=lambda: 946684800), /):
+    return dt
+"""
+    )
+    assert module.foo() == datetime(2000, 1, 1, tzinfo=timezone.utc)
+    assert module.foo(0) == datetime(1970, 1, 1, tzinfo=timezone.utc)