# HG changeset patch
# User ijl <ijl@mailbox.org>
# Date 1595553925 0
#      Fri Jul 24 01:25:25 2020 +0000
# Node ID ac110ee6b3e99b7c9633ee963d01c0780f5f2630
# Parent  b0c889bccb37e811fbb6b3d3b42f9be5d956f38d
OPT_PASSTHROUGH_DATACLASS

diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -115,7 +115,8 @@
 to the standard library. It can be disabled with
 `orjson.OPT_PASSTHROUGH_SUBCLASS`.`dataclasses.dataclass` instances
 are now serialized by default and cannot be customized in a
-`default` function. `uuid.UUID` instances are serialized by default.
+`default` function unless `option=orjson.OPT_PASSTHROUGH_DATACLASS` is
+specified. `uuid.UUID` instances are serialized by default.
 For any type that is now serialized,
 implementations in a `default` function and options enabling them can be
 removed but do not need to be. There was no change in deserialization.
@@ -404,6 +405,38 @@
 b'"1970-01-01T00:00:00"'
 ```
 
+##### OPT_PASSTHROUGH_DATACLASS
+
+Passthrough `dataclasses.dataclass` instances to `default`. This allows
+customizing their output but is much slower.
+
+
+```python
+>>> import orjson, dataclasses
+>>>
+@dataclasses.dataclass
+class User:
+    id: str
+    name: str
+    password: str
+
+def default(obj):
+    if isinstance(obj, User):
+        return {"id": obj.id, "name": obj.name}
+    raise TypeError
+
+>>> orjson.dumps(User("3b1", "asd", "zxc"))
+b'{"id":"3b1","name":"asd","password":"zxc"}'
+>>> orjson.dumps(User("3b1", "asd", "zxc"), option=orjson.OPT_PASSTHROUGH_DATACLASS)
+TypeError: Type is not JSON serializable: User
+>>> orjson.dumps(
+        User("3b1", "asd", "zxc"),
+        option=orjson.OPT_PASSTHROUGH_DATACLASS,
+        default=default,
+    )
+b'{"id":"3b1","name":"asd"}'
+```
+
 ##### OPT_PASSTHROUGH_DATETIME
 
 Passthrough `datetime.datetime`, `datetime.date`, and `datetime.time` instances
diff --git a/orjson.pyi b/orjson.pyi
--- a/orjson.pyi
+++ b/orjson.pyi
@@ -17,6 +17,7 @@
 OPT_NAIVE_UTC: int
 OPT_NON_STR_KEYS: int
 OPT_OMIT_MICROSECONDS: int
+OPT_PASSTHROUGH_DATACLASS: int
 OPT_PASSTHROUGH_DATETIME: int
 OPT_PASSTHROUGH_SUBCLASS: int
 OPT_SERIALIZE_DATACLASS: int
diff --git a/src/lib.rs b/src/lib.rs
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -106,6 +106,11 @@
     opt!(mptr, "OPT_OMIT_MICROSECONDS\0", opt::OMIT_MICROSECONDS);
     opt!(
         mptr,
+        "OPT_PASSTHROUGH_DATACLASS\0",
+        opt::PASSTHROUGH_DATACLASS
+    );
+    opt!(
+        mptr,
         "OPT_PASSTHROUGH_DATETIME\0",
         opt::PASSTHROUGH_DATETIME
     );
diff --git a/src/opt.rs b/src/opt.rs
--- a/src/opt.rs
+++ b/src/opt.rs
@@ -13,6 +13,7 @@
 pub const PASSTHROUGH_SUBCLASS: Opt = 1 << 8;
 pub const PASSTHROUGH_DATETIME: Opt = 1 << 9;
 pub const APPEND_NEWLINE: Opt = 1 << 10;
+pub const PASSTHROUGH_DATACLASS: Opt = 1 << 11;
 
 // deprecated
 pub const SERIALIZE_DATACLASS: Opt = 0;
@@ -20,7 +21,8 @@
 
 pub const SORT_OR_NON_STR_KEYS: Opt = SORT_KEYS | NON_STR_KEYS;
 
-pub const NOT_PASSTHROUGH: Opt = !(PASSTHROUGH_DATETIME | PASSTHROUGH_SUBCLASS);
+pub const NOT_PASSTHROUGH: Opt =
+    !(PASSTHROUGH_DATETIME | PASSTHROUGH_DATACLASS | PASSTHROUGH_SUBCLASS);
 
 pub const MAX_OPT: i32 = (APPEND_NEWLINE
     | INDENT_2
@@ -28,6 +30,7 @@
     | NON_STR_KEYS
     | OMIT_MICROSECONDS
     | PASSTHROUGH_DATETIME
+    | PASSTHROUGH_DATACLASS
     | PASSTHROUGH_SUBCLASS
     | SERIALIZE_DATACLASS
     | SERIALIZE_NUMPY
diff --git a/src/serialize/encode.rs b/src/serialize/encode.rs
--- a/src/serialize/encode.rs
+++ b/src/serialize/encode.rs
@@ -143,7 +143,9 @@
             && opts & PASSTHROUGH_SUBCLASS == 0
         {
             ObType::Dict
-        } else if ffi!(PyDict_Contains((*ob_type).tp_dict, DATACLASS_FIELDS_STR)) == 1 {
+        } else if opts & PASSTHROUGH_DATACLASS == 0
+            && ffi!(PyDict_Contains((*ob_type).tp_dict, DATACLASS_FIELDS_STR)) == 1
+        {
             ObType::Dataclass
         } else if opts & SERIALIZE_NUMPY != 0 && is_numpy_scalar(ob_type) {
             ObType::NumpyScalar
diff --git a/test/test_api.py b/test/test_api.py
--- a/test/test_api.py
+++ b/test/test_api.py
@@ -93,7 +93,7 @@
         dumps() option out of range high
         """
         with self.assertRaises(orjson.JSONEncodeError):
-            orjson.dumps(True, option=1 << 11)
+            orjson.dumps(True, option=1 << 12)
 
     def test_opts_multiple(self):
         """
diff --git a/test/test_dataclass.py b/test/test_dataclass.py
--- a/test/test_dataclass.py
+++ b/test/test_dataclass.py
@@ -2,7 +2,7 @@
 
 import unittest
 import uuid
-from dataclasses import InitVar, dataclass, field
+from dataclasses import InitVar, asdict, dataclass, field
 from enum import Enum
 from typing import ClassVar, Dict, Optional
 
@@ -250,3 +250,37 @@
             orjson.dumps(obj, option=orjson.OPT_SERIALIZE_DATACLASS),
             b'{"name":"a","number":1,"sub":null}',
         )
+
+
+class DataclassPassthroughTests(unittest.TestCase):
+    def test_dataclass_passthrough_raise(self):
+        """
+        dumps() dataclass passes to default with OPT_PASSTHROUGH_DATACLASS
+        """
+        obj = Dataclass1("a", 1, None)
+        with self.assertRaises(orjson.JSONEncodeError):
+            orjson.dumps(obj, option=orjson.OPT_PASSTHROUGH_DATACLASS)
+        with self.assertRaises(orjson.JSONEncodeError):
+            orjson.dumps(
+                InitDataclass("zxc", "vbn"), option=orjson.OPT_PASSTHROUGH_DATACLASS
+            )
+
+    def test_dataclass_passthrough_default(self):
+        """
+        dumps() dataclass passes to default with OPT_PASSTHROUGH_DATACLASS
+        """
+        obj = Dataclass1("a", 1, None)
+        self.assertEqual(
+            orjson.dumps(obj, option=orjson.OPT_PASSTHROUGH_DATACLASS, default=asdict),
+            b'{"name":"a","number":1,"sub":null}',
+        )
+
+        def default(obj):
+            if isinstance(obj, Dataclass1):
+                return {"name": obj.name, "number": obj.number}
+            raise TypeError
+
+        self.assertEqual(
+            orjson.dumps(obj, option=orjson.OPT_PASSTHROUGH_DATACLASS, default=default),
+            b'{"name":"a","number":1}',
+        )
diff --git a/test/test_numpy.py b/test/test_numpy.py
--- a/test/test_numpy.py
+++ b/test/test_numpy.py
@@ -2,8 +2,9 @@
 
 import unittest
 
+import pytest
+
 import orjson
-import pytest
 
 try:
     import numpy