Repository: pydantic/pydantic

Issue:
Required field default value inconsistent (None vs. Ellipsis) between statically and dynamically created models with v1.7.3
### Checks

* [x] I added a descriptive title to this issue
* [x] I have searched (google, github) for similar issues and couldn't find anything
* [x] I have read and followed [the docs](https://pydantic-docs.helpmanual.io/) and still think this is a bug

<!-- Sorry to sound so draconian, but every second saved replying to issues is time spend improving pydantic :-) -->

# Bug

Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:
```
             pydantic version: 1.7.3
            pydantic compiled: True
                 install path: /usr/local/lib/python3.8/site-packages/pydantic
               python version: 3.8.6 (default, Nov 25 2020, 02:47:44)  [GCC 8.3.0]
                     platform: Linux-5.6.0-1033-oem-x86_64-with-glibc2.2.5
     optional deps. installed: []
```
<!-- or if you're using pydantic prior to v1.3, manually include: OS, python version and pydantic version -->

<!-- Please read the [docs](https://pydantic-docs.helpmanual.io/) and search through issues to
confirm your bug hasn't already been reported. -->

<!-- Where possible please include a self-contained code snippet describing your bug: -->

```py
from typing import Type, Dict

import pydantic.utils
from pydantic import BaseModel, create_model
from pydantic.fields import ModelField, UndefinedType


class A(BaseModel):
    x: int
    y: float
    z: str


def dynamic_model():
    return create_model("A", x=(int, ...), y=(float, ...), z=(str, ...))


DYNAMIC_MODEL = dynamic_model()


def get_field_name_to_pydantic_field(model_type: Type[BaseModel]) -> Dict[str, ModelField]:
    return {field.name: field for field in model_type.__fields__.values()}


def assert_model_fields(mf1, mf2):
    assert mf1.type_ is mf2.type_
    assert mf1.name == mf2.name
    assert mf1.default == mf2.default
    assert mf1.required == mf2.required

    if isinstance(mf1.field_info.default, UndefinedType):
        assert isinstance(mf2.field_info.default, UndefinedType)
    else:
        assert mf1.field_info.default == mf2.field_info.default
    assert mf1.field_info.const == mf2.field_info.const
    assert mf1.field_info.extra == mf2.field_info.extra


def test_statically_and_dynamically_created_equivalent_models():
    print(f"\n{pydantic.utils.version_info()}")

    print("\nCreated statically:")
    for n, mf in get_field_name_to_pydantic_field(A).items():
        print(n, mf, mf.default)

    print("\nCreated dynamically:")
    for n, mf in get_field_name_to_pydantic_field(DYNAMIC_MODEL).items():
        print(n, mf, mf.default)

    for field_name in A.__fields__:
        assert_model_fields(A.__fields__[field_name], DYNAMIC_MODEL.__fields__[field_name])
```

This bug _might_ be related to https://github.com/samuelcolvin/pydantic/issues/2142 and https://github.com/samuelcolvin/pydantic/commit/9ae40a209f929e421736a69d093d01749861c772 .

It seems `pydantic` sets the default value of a required field of a statically created model as `None`. This was the case until `v1.7.2` for the required fields of dynamically created models. However with the `v1.7.3` there seems to be an inconsistent behaviour where the default value for the required fields of dynamically created models are set to be `Ellipsis`. I'm not aware whether this was intentional, or consistent behaviour between statically and dynamically created models is sought after but I wanted to point that out in case it is a regression.

Here's a dockerized version of the tests: https://github.com/emreay-/pydantic-default-value-inconsistency-test

The output for `pydantic==1.7.2` (warnings are pytest cache warnings):
```
=============================================================================================== test session starts ===============================================================================================
platform linux -- Python 3.8.6, pytest-6.1.2, py-1.9.0, pluggy-0.13.1
rootdir: /
collected 1 item                                                                                                                                                                                                  

pydantic_default_issue.py 
             pydantic version: 1.7.2
            pydantic compiled: True
                 install path: /usr/local/lib/python3.8/site-packages/pydantic
               python version: 3.8.6 (default, Nov 25 2020, 02:47:44)  [GCC 8.3.0]
                     platform: Linux-5.6.0-1033-oem-x86_64-with-glibc2.2.5
     optional deps. installed: []

Created statically:
x name='x' type=int required=True None
y name='y' type=float required=True None
z name='z' type=str required=True None

Created dynamically:
x name='x' type=int required=True None
y name='y' type=float required=True None
z name='z' type=str required=True None
.

========================================================================================== 1 passed, 2 warnings in 0.05s ==========================================================================================
```

The output for `pydantic==1.7.3` (warnings are pytest cache warnings):
```
=============================================================================================== test session starts ===============================================================================================
platform linux -- Python 3.8.6, pytest-6.1.2, py-1.9.0, pluggy-0.13.1
rootdir: /
collected 1 item                                                                                                                                                                                                  

pydantic_default_issue.py 
             pydantic version: 1.7.3
            pydantic compiled: True
                 install path: /usr/local/lib/python3.8/site-packages/pydantic
               python version: 3.8.6 (default, Nov 25 2020, 02:47:44)  [GCC 8.3.0]
                     platform: Linux-5.6.0-1033-oem-x86_64-with-glibc2.2.5
     optional deps. installed: []

Created statically:
x name='x' type=int required=True None
y name='y' type=float required=True None
z name='z' type=str required=True None

Created dynamically:
x name='x' type=int required=True Ellipsis
y name='y' type=float required=True Ellipsis
z name='z' type=str required=True Ellipsis
F

==================================================================================================== FAILURES =====================================================================================================
____________________________________________________________________________ test_statically_and_dynamically_created_equivalent_models ____________________________________________________________________________

    def test_statically_and_dynamically_created_equivalent_models():
        print(f"\n{pydantic.utils.version_info()}")
    
        print("\nCreated statically:")
        for n, mf in get_field_name_to_pydantic_field(A).items():
            print(n, mf, mf.default)
    
        print("\nCreated dynamically:")
        for n, mf in get_field_name_to_pydantic_field(DYNAMIC_MODEL).items():
            print(n, mf, mf.default)
    
        for field_name in A.__fields__:
>           assert_model_fields(A.__fields__[field_name], DYNAMIC_MODEL.__fields__[field_name])

pydantic_default_issue.py:51: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

mf1 = ModelField(name='x', type=int, required=True), mf2 = ModelField(name='x', type=int, required=True)

    def assert_model_fields(mf1, mf2):
        assert mf1.type_ is mf2.type_
        assert mf1.name == mf2.name
>       assert mf1.default == mf2.default
E       AssertionError: assert None == Ellipsis
E        +  where None = ModelField(name='x', type=int, required=True).default
E        +  and   Ellipsis = ModelField(name='x', type=int, required=True).default

pydantic_default_issue.py:28: AssertionError
============================================================================================= short test summary info =============================================================================================
FAILED pydantic_default_issue.py::test_statically_and_dynamically_created_equivalent_models - AssertionError: assert None == Ellipsis
========================================================================================== 1 failed, 3 warnings in 0.07s ==========================================================================================
```


Discussion:

Resolving patch:
diff --git a/pydantic/fields.py b/pydantic/fields.py
--- a/pydantic/fields.py
+++ b/pydantic/fields.py
@@ -307,7 +307,7 @@ def infer(
         required: 'BoolUndefined' = Undefined
         if value is Required:
             required = True
-            value = Ellipsis
+            value = None
         elif value is not Undefined:
             required = False
         field_info.alias = field_info.alias or field_info_from_config.get('alias')
diff --git a/pydantic/main.py b/pydantic/main.py
--- a/pydantic/main.py
+++ b/pydantic/main.py
@@ -788,12 +788,12 @@ def _iter(
         value_include = ValueItems(self, include) if include else None
 
         for field_key, v in self.__dict__.items():
-            if (
-                (allowed_keys is not None and field_key not in allowed_keys)
-                or (exclude_none and v is None)
-                or (exclude_defaults and getattr(self.__fields__.get(field_key), 'default', _missing) == v)
-            ):
+            if (allowed_keys is not None and field_key not in allowed_keys) or (exclude_none and v is None):
                 continue
+            if exclude_defaults:
+                model_field = self.__fields__.get(field_key)
+                if not getattr(model_field, 'required', True) and getattr(model_field, 'default', _missing) == v:
+                    continue
             if by_alias and field_key in self.__fields__:
                 dict_key = self.__fields__[field_key].alias
             else:


Test patch:
diff --git a/tests/test_create_model.py b/tests/test_create_model.py
--- a/tests/test_create_model.py
+++ b/tests/test_create_model.py
@@ -182,3 +182,15 @@ class Model(BaseModel):
     assert model.__fields__.keys() == {'a', 'b'}
     assert model2.__fields__.keys() == {'a', 'c'}
     assert model3.__fields__.keys() == {'a', 'b', 'd'}
+
+
+def test_dynamic_and_static():
+    class A(BaseModel):
+        x: int
+        y: float
+        z: str
+
+    DynamicA = create_model('A', x=(int, ...), y=(float, ...), z=(str, ...))
+
+    for field_name in ('x', 'y', 'z'):
+        assert A.__fields__[field_name].default == DynamicA.__fields__[field_name].default
diff --git a/tests/test_dataclasses.py b/tests/test_dataclasses.py
--- a/tests/test_dataclasses.py
+++ b/tests/test_dataclasses.py
@@ -407,7 +407,7 @@ class User:
     fields = user.__pydantic_model__.__fields__
 
     assert fields['id'].required is True
-    assert fields['id'].default is Ellipsis
+    assert fields['id'].default is None
 
     assert fields['name'].required is False
     assert fields['name'].default == 'John Doe'
@@ -426,7 +426,7 @@ class User:
     fields = user.__pydantic_model__.__fields__
 
     assert fields['id'].required is True
-    assert fields['id'].default is Ellipsis
+    assert fields['id'].default is None
 
     assert fields['aliases'].required is False
     assert fields['aliases'].default == {'John': 'Joey'}