Repository: marshmallow-code/marshmallow

Issue:
TypeError thrown with many=True on non-iterable types
With `3.0.0b13` this passes:

```python
class Sch(Schema):
    foo = fields.Str()

for p in [False, 1, 1.2]:
    with pytest.raises(TypeError):
        Sch(many=True).load(p)
```

I think `Schema.load()` should rather catch invalid types and raise `ValidationError`?

Discussion:

Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index a65b93a5..2a1b44f9 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,6 +1,15 @@
 Changelog
 ---------
 
+2.15.6 (unreleased)
++++++++++++++++++++
+
+Bug fixes:
+
+- Prevent ``TypeError`` when a non-collection is passed to a ``Schema`` with ``many=True``.
+  Instead, raise ``ValidationError`` with ``{'_schema': ['Invalid input type.']}`` (:issue:`906`).
+  
+
 2.15.5 (2018-09-15)
 +++++++++++++++++++
 
diff --git a/marshmallow/marshalling.py b/marshmallow/marshalling.py
index 9fcae405..7ab8713f 100644
--- a/marshmallow/marshalling.py
+++ b/marshmallow/marshalling.py
@@ -220,20 +220,26 @@ class Unmarshaller(ErrorStore):
         :return: A dictionary of the deserialized data.
         """
         if many and data is not None:
-            self._pending = True
-            ret = [self.deserialize(d, fields_dict, many=False,
-                        partial=partial, dict_class=dict_class,
-                        index=idx, index_errors=index_errors)
-                    for idx, d in enumerate(data)]
+            if not is_collection(data):
+                errors = self.get_errors(index=index)
+                self.error_field_names.append(SCHEMA)
+                errors[SCHEMA] = ['Invalid input type.']
+                ret = []
+            else:
+                self._pending = True
+                ret = [self.deserialize(d, fields_dict, many=False,
+                            partial=partial, dict_class=dict_class,
+                            index=idx, index_errors=index_errors)
+                        for idx, d in enumerate(data)]
 
-            self._pending = False
-            if self.errors:
-                raise ValidationError(
-                    self.errors,
-                    field_names=self.error_field_names,
-                    fields=self.error_fields,
-                    data=ret,
-                )
+                self._pending = False
+                if self.errors:
+                    raise ValidationError(
+                        self.errors,
+                        field_names=self.error_field_names,
+                        fields=self.error_fields,
+                        data=ret,
+                    )
             return ret
         if data is not None:
             partial_is_collection = is_collection(partial)


Test patch:
diff --git a/tests/test_schema.py b/tests/test_schema.py
index 7f0e8cb8..cccc7c91 100755
--- a/tests/test_schema.py
+++ b/tests/test_schema.py
@@ -279,6 +279,16 @@ def test_load_many():
     assert type(result.data[0]) == User
     assert result.data[0].name == 'Mick'
 
+# regression test for https://github.com/marshmallow-code/marshmallow/issues/906
+@pytest.mark.parametrize('val', (False, 1, 1.2, object(), {}, {'1': 2}, 'lol'))
+def test_load_many_invalid_input_type(val):
+    class Sch(Schema):
+        name = fields.Str()
+    with pytest.raises(ValidationError) as e:
+        Sch(strict=True, many=True).load(val)
+    assert e.value.messages == {'_schema': ['Invalid input type.']}
+    assert '_schema' in e.value.field_names
+
 def test_loads_returns_an_unmarshalresult(user):
     s = UserSchema()
     result = s.loads(json.dumps({'name': 'Monty'}))