Repository: marshmallow-code/marshmallow
Pull request #1448 (2019-11-04 15:38:04)

Fix logic for field both load_only and dump_only
I just stumbled upon this.

I don't really see the use case for a field both `dump_only` and `load_only` but I don't think it is forbidden, is it?

Without the fix, due to the `elif`, the `dump_only` attribute is ignored.


Patch:
diff --git a/src/marshmallow/schema.py b/src/marshmallow/schema.py
index 7265514f..8e1190c9 100644
--- a/src/marshmallow/schema.py
+++ b/src/marshmallow/schema.py
@@ -969,12 +969,9 @@ class Schema(base.SchemaABC, metaclass=SchemaMeta):
 
         load_fields, dump_fields = self.dict_class(), self.dict_class()
         for field_name, field_obj in fields_dict.items():
-            if field_obj.load_only:
-                load_fields[field_name] = field_obj
-            elif field_obj.dump_only:
-                dump_fields[field_name] = field_obj
-            else:
+            if not field_obj.dump_only:
                 load_fields[field_name] = field_obj
+            if not field_obj.load_only:
                 dump_fields[field_name] = field_obj
 
         dump_data_keys = [


Test patch:
diff --git a/tests/test_deserialization.py b/tests/test_deserialization.py
index e82df008..b71fed96 100644
--- a/tests/test_deserialization.py
+++ b/tests/test_deserialization.py
@@ -1308,12 +1308,19 @@ class TestSchemaDeserialization:
         class AliasingUserSerializer(Schema):
             name = fields.String()
             years = fields.Integer(dump_only=True)
+            size = fields.Integer(dump_only=True, load_only=True)
             nicknames = fields.List(fields.Str(), dump_only=True)
 
-        data = {"name": "Mick", "years": "42", "nicknames": ["Your Majesty", "Brenda"]}
+        data = {
+            "name": "Mick",
+            "years": "42",
+            "size": "12",
+            "nicknames": ["Your Majesty", "Brenda"],
+        }
         result = AliasingUserSerializer(unknown=EXCLUDE).load(data)
         assert result["name"] == "Mick"
         assert "years" not in result
+        assert "size" not in result
         assert "nicknames" not in result
 
     def test_deserialize_with_missing_param_value(self):
diff --git a/tests/test_serialization.py b/tests/test_serialization.py
index 8c67e3f3..7a25bd73 100644
--- a/tests/test_serialization.py
+++ b/tests/test_serialization.py
@@ -77,6 +77,25 @@ class TestFieldSerialization:
         with pytest.raises(AttributeError):
             field.serialize("key", user)
 
+    def test_serialize_with_load_only_param(self):
+        class AliasingUserSerializer(Schema):
+            name = fields.String()
+            years = fields.Integer(load_only=True)
+            size = fields.Integer(dump_only=True, load_only=True)
+            nicknames = fields.List(fields.Str(), load_only=True)
+
+        data = {
+            "name": "Mick",
+            "years": "42",
+            "size": "12",
+            "nicknames": ["Your Majesty", "Brenda"],
+        }
+        result = AliasingUserSerializer().dump(data)
+        assert result["name"] == "Mick"
+        assert "years" not in result
+        assert "size" not in result
+        assert "nicknames" not in result
+
     def test_function_field_load_only(self):
         field = fields.Function(deserialize=lambda obj: None)
         assert field.load_only