Repository: pydantic/pydantic

Issue:
Can Field been used as function default argument value?
# Feature Request

Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:
```
             pydantic version: 1.5a1
            pydantic compiled: True
                 install path: /home/xxx/.conda/envs/xxx/lib/python3.7/site-packages/pydantic
               python version: 3.7.4 (default, Aug 13 2019, 20:35:49)  [GCC 7.3.0]
                     platform: Linux-4.18.0-80.el8.x86_64-x86_64-with-centos-8.0.1905-Core
     optional deps. installed: ['typing-extensions', 'email-validator']
```
Hi, I am trying the function decorator validate_arguments. Is it possible use Field as the default argument value like this?
```py
from datetime import datetime
from pydantic import validate_arguments, Field

@validate_arguments
def foo(dt: datetime = Field(default_factory=datetime.now)):
    print(dt)

```



Discussion:
This is not currently possible. It won't be added immediately, but I'd definitely consider adding something like this in future.

The way I had previously thought it would work, would be to add a model as an argument to `validate_arguments`, so it would be something like:

```py
from datetime import datetime
from pydantic import BaseModel, validate_arguments, Field

class FooModel(BaseModel):
    dt: datetime = Field(default_factory=datetime.now)

@validate_arguments(model=FooModel)
def foo(dt: datetime):
    print(dt)
```
Then `validate_arguments` is just checking that `FooModel` matches the arguments of `foo()`.

Your `Field` approach would be slightly shorter, but might upset mypy. I'd be open to considering both.
OK, thanks. I will keep this issue open if necessary.
I didn't even realise that Field wasn't supported in `validate_arguments` (didn't read the docs properly), so I didn't go looking for an issue until I tried to use it for a default argument. I've submitted a PR that fixes this particular case and doesn't break any of the other tests, but I've probably missed something so I'd welcome someone else's opinion on this.

Also, mypy seems happy with this, it doesn't complain about the default value, and if you pass a value of a different type it will catch it
For reference, the way I am using this at the moment:

```python
class Line(BaseModel):
    key: Any = Field(..., description="An identifier for what to move")
    start: float = Field(..., description="Centre point of the first point of the line")
    stop: float = Field(..., description="Centre point of the last point of the line")
    num: int = Field(..., ge=1, description="Number of points to produce")

    @classmethod
    @validate_arguments
    def bounded(
        cls,
        key=key,
        lower: float = Field(..., description="Lower bound of the first point of the line"),
        upper: float = Field(..., description="Upper bound of the last point of the line"),
        num: int = num,
    ):
        half_step = (upper - lower) / num / 2
        return cls(key=key, start=lower+half_step, stop=upper-half_step, num=num)

    ...
```

I then use the Field info to make a JSON schema of the classes, and create a GraphQL query of both class constructors and alternative classmethod constructors

The re-use of the descriptions from Field definitions is a useful pattern

Resolving patch:
diff --git a/docs/examples/validation_decorator_field.py b/docs/examples/validation_decorator_field.py
new file mode 100644
--- /dev/null
+++ b/docs/examples/validation_decorator_field.py
@@ -0,0 +1,22 @@
+from datetime import datetime
+from pydantic import validate_arguments, Field, ValidationError
+from pydantic.typing import Annotated
+
+
+@validate_arguments
+def how_many(num: Annotated[int, Field(gt=10)]):
+    return num
+
+
+try:
+    how_many(1)
+except ValidationError as e:
+    print(e)
+
+
+@validate_arguments
+def when(dt: datetime = Field(default_factory=datetime.now)):
+    return dt
+
+
+print(type(when()))
diff --git a/pydantic/decorator.py b/pydantic/decorator.py
--- a/pydantic/decorator.py
+++ b/pydantic/decorator.py
@@ -184,7 +184,7 @@ def build_values(self, args: Tuple[Any, ...], kwargs: Dict[str, Any]) -> Dict[st
         return values
 
     def execute(self, m: BaseModel) -> Any:
-        d = {k: v for k, v in m._iter() if k in m.__fields_set__}
+        d = {k: v for k, v in m._iter() if k in m.__fields_set__ or m.__fields__[k].default_factory}
         var_kwargs = d.pop(self.v_kwargs_name, {})
 
         if self.v_args_name in d:


Test patch:
diff --git a/tests/test_decorator.py b/tests/test_decorator.py
--- a/tests/test_decorator.py
+++ b/tests/test_decorator.py
@@ -3,12 +3,14 @@
 import sys
 from pathlib import Path
 from typing import List
+from unittest.mock import ANY
 
 import pytest
 
-from pydantic import BaseModel, ValidationError, validate_arguments
+from pydantic import BaseModel, Field, ValidationError, validate_arguments
 from pydantic.decorator import ValidatedFunction
 from pydantic.errors import ConfigError
+from pydantic.typing import Annotated
 
 skip_pre_38 = pytest.mark.skipif(sys.version_info < (3, 8), reason='testing >= 3.8 behaviour only')
 
@@ -142,6 +144,24 @@ def foo(a, b, *args, d=3, **kwargs):
     assert foo(1, 2, kwargs=4, e=5) == "a=1, b=2, args=(), d=3, kwargs={'kwargs': 4, 'e': 5}"
 
 
+def test_field_can_provide_factory() -> None:
+    @validate_arguments
+    def foo(a: int, b: int = Field(default_factory=lambda: 99), *args: int) -> int:
+        """mypy is happy with this"""
+        return a + b + sum(args)
+
+    assert foo(3) == 102
+    assert foo(1, 2, 3) == 6
+
+
+@pytest.mark.skipif(not Annotated, reason='typing_extensions not installed')
+def test_annotated_field_can_provide_factory() -> None:
+    @validate_arguments
+    def foo2(a: int, b: Annotated[int, Field(default_factory=lambda: 99)] = ANY, *args: int) -> int:
+        """mypy reports Incompatible default for argument "b" if we don't supply ANY as default"""
+        return a + b + sum(args)
+
+
 @skip_pre_38
 def test_positional_only(create_module):
     module = create_module(