Repository: marshmallow-code/marshmallow

Issue:
How to deal with a field with both required and missing?
@taion (https://github.com/marshmallow-code/marshmallow/pull/756#issuecomment-436054072):
> [Since #756], missing now has no effect if required is specified, as the required check is made before the missing logic is applied.
>
> I think it would make more sense to restore the old behavior – as with missing implicitly overriding allow_none, it should also override required.

This is debatable.

Another option could be to raise an Exception.

If we keep current behaviour, we should at least document it.

Discussion:

Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index bb0fe839..e1b90723 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -15,6 +15,8 @@ Other changes:
 
 - Add ``marshmallow.__version_info__`` (:pr:`1074`).
 - Remove the ``marshmallow.marshalling`` internal module (:pr:`1070`).
+- A ``ValueError`` is raised when the ``missing`` parameter is passed
+  for required fields (:issue:`1040`).
 
 3.0.0rc1 (2018-11-29)
 +++++++++++++++++++++
diff --git a/marshmallow/fields.py b/marshmallow/fields.py
index e45bcaac..636fe3a5 100644
--- a/marshmallow/fields.py
+++ b/marshmallow/fields.py
@@ -148,7 +148,6 @@ class Field(FieldABC):
                 'or a collection of callables.',
             )
 
-        self.required = required
         # If missing=None, None should be considered valid by default
         if allow_none is None:
             if missing is None:
@@ -159,6 +158,9 @@ class Field(FieldABC):
             self.allow_none = allow_none
         self.load_only = load_only
         self.dump_only = dump_only
+        if required is True and missing is not missing_:
+            raise ValueError("'missing' must not be set for required fields.")
+        self.required = required
         self.missing = missing
         self.metadata = metadata
         self._creation_index = Field._creation_index


Test patch:
diff --git a/tests/test_fields.py b/tests/test_fields.py
index 6dfacc77..e4c8b11a 100644
--- a/tests/test_fields.py
+++ b/tests/test_fields.py
@@ -41,6 +41,10 @@ class TestField:
         with pytest.raises(ValueError, match='must be a callable'):
             fields.Field(validate='notcallable')
 
+    def test_error_raised_if_missing_is_set_on_required_field(self):
+        with pytest.raises(ValueError, match="'missing' must not be set for required fields"):
+            fields.Field(required=True, missing=42)
+
     def test_custom_field_receives_attr_and_obj(self):
         class MyField(fields.Field):
             def _deserialize(self, val, attr, data):