Repository: marshmallow-code/marshmallow
Pull request #1633 (2020-07-16 12:49:50)

Boolean can handle unhashable type
Excepted: 
```python
class BrandSchema():
    has_new_product = fields.Boolean(attribute="new_products")

res = BrandSchema().dump({"new_products": [Product(), ...])
# {"has_new_product": True}
```

but it raise unhashable type exception because `value in self.truthy`.
so add defense code. thank you.

sloria: We try to avoid isinstance checks when serializing as they can impact performance when serializing many objects. For now I'd suggest something along the lines of

```python
class BrandSchema():
    has_new_product = fields.Function(lambda obj: bool(obj['new_projects']))
```

Will that address your use case?
jun0jang: actually now i did same using method field.  but i think function field is for much more complex thing.
primitive type field is readability and maintenance than function field.

i agree performance is very important. for libraries, it's even more important.
jun0jang: actually now i did same using method field.  but i think function field is for much more complex thing.
primitive type field is readability and maintenance than function field.

i agree performance is very important. for libraries, it's even more important. but t's also important to work well.
so how did you think about doing this?

```python
try:
    if value in self.truthy:
       ...
except TypeError:
    pass

return bool(value)
```
sloria: I think that solution makes sense. We use a similar approach for `validate.OneOf` and `validate.NoneOf`.
sloria: I'm unsure if this should be considered as a breaking change. Previously `Boolean` would reject lists and dicts (albeit ungracefully). This changes accepts those. Perhaps this should go into 4.0?

@lafrech @deckar01 wdyt?
lafrech: I say non-breaking because

- by API contract, we don't validate on dump 
- it used to be an exception

Patch:
diff --git a/AUTHORS.rst b/AUTHORS.rst
index cb67ab7f..183590fa 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -151,3 +151,4 @@ Contributors (chronological)
 - Ram Rachum `@cool-RR <https://github.com/cool-RR>`_
 - `@weeix <https://github.com/weeix>`_
 - Juan Norris `@juannorris <https://github.com/juannorris>`_
+- 장준영 `@jun0jang <https://github.com/jun0jang>`_
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 5c384e6d..5165019f 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,6 +1,14 @@
 Changelog
 ---------
 
+3.7.1 (unreleased)
+******************
+
+Bug fixes:
+
+- ``fields.Boolean`` correctly serializes non-hashable types (:pr:`1633`).
+  Thanks :user:`jun0jang` for the PR.
+
 3.7.0 (2020-07-08)
 ******************
 
diff --git a/src/marshmallow/fields.py b/src/marshmallow/fields.py
index c727292b..a725c132 100644
--- a/src/marshmallow/fields.py
+++ b/src/marshmallow/fields.py
@@ -1112,10 +1112,14 @@ class Boolean(Field):
     def _serialize(self, value, attr, obj, **kwargs):
         if value is None:
             return None
-        elif value in self.truthy:
-            return True
-        elif value in self.falsy:
-            return False
+
+        try:
+            if value in self.truthy:
+                return True
+            elif value in self.falsy:
+                return False
+        except TypeError:
+            pass
 
         return bool(value)
 


Test patch:
diff --git a/tests/test_schema.py b/tests/test_schema.py
index cc06200e..85646754 100644
--- a/tests/test_schema.py
+++ b/tests/test_schema.py
@@ -162,6 +162,16 @@ def test_dump_many():
     assert data[0] == s.dump(u1)
 
 
+@pytest.mark.parametrize("value", [[], {}, [1], {1: 1}])
+def test_boolean_can_dump_unhashable(value):
+    class MySchema(Schema):
+        has_items = fields.Boolean()
+
+    schema = MySchema()
+    data = schema.dump({"has_items": value})
+    assert data["has_items"] is bool(value)
+
+
 def test_multiple_errors_can_be_stored_for_a_given_index():
     class MySchema(Schema):
         foo = fields.Str(validate=lambda x: len(x) > 3)