Repository: ramonhagenaars/jsons

Issue:
Serialization of unspecified length of Tuple fails
The following serialization fails when I use `strict=True`, I am not sure whether this is expected behavior or not.

```
>>> from typing import Tuple
>>> from dataclasses import dataclass
>>> import jsons
>>> @dataclass(frozen=True)
... class A:
...     x: Tuple[str, ...]
... 
>>> jsons.dumps(A('abc'), strict=True)
```

Error:
```
Traceback (most recent call last):
  File "~/.pyenv/versions/forms/lib/python3.7/site-packages/jsons/_dump_impl.py", line 62, in _do_dump
    result = serializer(obj, cls=cls, **kwargs)
  File "~/.pyenv/versions/forms/lib/python3.7/site-packages/jsons/serializers/default_object.py", line 92, in default_object_serializer
    fork_inst=fork_inst)
  File "~/.pyenv/versions/forms/lib/python3.7/site-packages/jsons/serializers/default_object.py", line 126, in _do_serialize
    **kwargs)
  File "~/.pyenv/versions/forms/lib/python3.7/site-packages/jsons/_dump_impl.py", line 57, in dump
    return _do_dump(obj, serializer, cls, initial, kwargs_)
  File "~/.pyenv/versions/forms/lib/python3.7/site-packages/jsons/_dump_impl.py", line 68, in _do_dump
    raise SerializationError(str(err))
jsons.exceptions.SerializationError: Not enough generic types (2) in typing.Tuple[str, ...], expected 3 to match the iterable of length 3
```

Discussion:

Patch:
diff --git a/README.md b/README.md
index ac05a16..17f98b9 100644
--- a/README.md
+++ b/README.md
@@ -87,6 +87,10 @@ list_of_tuples = jsons.load(some_dict, List[Tuple[AClass, AnotherClass]])
 
 ## Recent updates
 
+### 1.1.2
+
+- Bugfix: Dumping a tuple with ellipsis failed in strict mode.
+
 ### 1.1.1
 
   - Feature: Added a serializer for ``Union`` types.
@@ -120,11 +124,7 @@ list_of_tuples = jsons.load(some_dict, List[Tuple[AClass, AnotherClass]])
 
 ### 0.10.2
 
-  - Bugfix: Loading `Dict[K, V]` did not parse `K`.
-
-### 0.10.1
-
-  - Change: Correction of the type hints of `load`, `loads`, `loadb`.
+  - Bugfix: Loading `Dict[K, V]` did not parse `K
 
 
 ## Contributors
diff --git a/jsons/serializers/default_iterable.py b/jsons/serializers/default_iterable.py
index 9e26962..7032a80 100644
--- a/jsons/serializers/default_iterable.py
+++ b/jsons/serializers/default_iterable.py
@@ -35,7 +35,6 @@ def default_iterable_serializer(
     kwargs_.pop('_store_cls', None)
     if strict:
         cls_ = determine_cls(obj, cls)
-        # cls_ = cls or get_type(obj)  # Get the List[T] type from the instance.
         subclasses = _get_subclasses(obj, cls_)
     else:
         subclasses = _get_subclasses(obj, None)
diff --git a/jsons/serializers/default_primitive.py b/jsons/serializers/default_primitive.py
index 6fa0a59..074d30c 100644
--- a/jsons/serializers/default_primitive.py
+++ b/jsons/serializers/default_primitive.py
@@ -9,7 +9,7 @@ def default_primitive_serializer(obj: object,
     """
     Serialize a primitive; simply return the given ``obj``.
     :param obj: the primitive.
-    :param _: not used.
+    :param cls: the type of ``obj``.
     :return: ``obj``.
     """
     result = obj
diff --git a/jsons/serializers/default_tuple.py b/jsons/serializers/default_tuple.py
index aef627b..5b12961 100644
--- a/jsons/serializers/default_tuple.py
+++ b/jsons/serializers/default_tuple.py
@@ -1,19 +1,31 @@
-from typing import Union
+from typing import Union, Optional, Tuple
+
+from typish import get_args
+
+from jsons._compatibility_impl import tuple_with_ellipsis
 from jsons._dump_impl import dump
 from jsons.serializers.default_iterable import default_iterable_serializer
 
 
-def default_tuple_serializer(obj: tuple, **kwargs) -> Union[list, dict]:
+def default_tuple_serializer(obj: tuple,
+                             cls: Optional[type] = None,
+                             **kwargs) -> Union[list, dict]:
     """
     Serialize the given ``obj`` to a list of serialized objects.
     :param obj: the tuple that is to be serialized.
+    :param cls: the type of the ``obj``.
     :param kwargs: any keyword arguments that may be given to the serialization
     process.
     :return: a list of which all elements are serialized.
     """
     if hasattr(obj, '_fields'):
         return default_namedtuple_serializer(obj, **kwargs)
-    return default_iterable_serializer(obj, **kwargs)
+
+    cls_ = cls
+    if cls and tuple_with_ellipsis(cls):
+        cls_ = Tuple[(get_args(cls)[0],) * len(obj)]
+
+    return default_iterable_serializer(obj, cls_, **kwargs)
 
 
 def default_namedtuple_serializer(obj: tuple, **kwargs) -> dict:


Test patch:
diff --git a/tests/test_tuple.py b/tests/test_tuple.py
index f25bf8f..51ccc2e 100644
--- a/tests/test_tuple.py
+++ b/tests/test_tuple.py
@@ -14,6 +14,21 @@ class TestTuple(TestCase):
         self.assertEqual([1, 2, 3, [4, 5, ['2018-07-08T21:34:00Z']]],
                          jsons.dump(tup))
 
+    def test_dump_tuple_with_ellipsis(self):
+        class A:
+            def __init__(self, x: Tuple[str, ...]):
+                self.x = x
+
+        expected = {
+            'x': ['abc', 'def']
+        }
+
+        dumped1 = jsons.dump(A(('abc', 'def')), strict=True)
+        dumped2 = jsons.dump(A(('abc', 'def')), strict=False)
+
+        self.assertDictEqual(expected, dumped1)
+        self.assertDictEqual(expected, dumped2)
+
     def test_dump_namedtuple(self):
         T = namedtuple('T', ['x', 'y'])
         t = T(1, 2)