Repository: ramonhagenaars/jsons

Issue:
String deserialized as datetime despite target type annotation
This code:
```python
@dataclass
class Sample:
    prop: str

def unrelated_date_deserializer(obj: str, cls: type = datetime, **kwargs) -> datetime:
    return datetime.strptime(obj, '%Y')

jsons.set_deserializer(unrelated_date_deserializer, datetime)

json = {'prop': '1025'}
print(jsons.load(json, Sample, strict=True))
```
Outputs:
```python
Sample(prop=datetime.datetime(1025, 1, 1, 0, 0))
```
Shouldn't the `str` type annotation be used to decide whether to employ the deserializer or not?

Comments:

Patch:
diff --git a/README.md b/README.md
index bea7f72..6321d77 100644
--- a/README.md
+++ b/README.md
@@ -82,6 +82,10 @@ list_of_tuples = jsons.load(some_dict, List[Tuple[AClass, AnotherClass]])
 
 ## Recent updates
 
+### 1.6.3
+
+- Bugfix: a string was sometimes unintentionally parsed into a datetime.
+
 ### 1.6.2
 
 - Bugfix: `fork_inst`s were not propagated in `default_list_deserializer` (thanks to patrickguenther).
diff --git a/jsons/_load_impl.py b/jsons/_load_impl.py
index 2d2d322..724cdf2 100644
--- a/jsons/_load_impl.py
+++ b/jsons/_load_impl.py
@@ -79,6 +79,7 @@ def load(
         return json_obj
     if isinstance(cls, str):
         cls = get_cls_from_str(cls, json_obj, fork_inst)
+    original_cls = cls
     cls, meta_hints = _check_and_get_cls_and_meta_hints(
         json_obj, cls, fork_inst, kwargs.get('_inferred_cls', False))
 
@@ -88,12 +89,13 @@ def load(
     initial = kwargs.get('_initial', True)
 
     kwargs_ = {
+        'meta_hints': meta_hints,  # Overridable by kwargs.
+        **kwargs,
         'strict': strict,
         'fork_inst': fork_inst,
         'attr_getters': attr_getters,
-        'meta_hints': meta_hints,
         '_initial': False,
-        **kwargs
+        '_inferred_cls': cls is not original_cls,
     }
 
     return _do_load(json_obj, deserializer, cls, initial, **kwargs_)
diff --git a/jsons/_package_info.py b/jsons/_package_info.py
index bc37be5..f4781c8 100644
--- a/jsons/_package_info.py
+++ b/jsons/_package_info.py
@@ -1,5 +1,5 @@
 __title__ = 'jsons'
-__version__ = '1.6.2'
+__version__ = '1.6.3'
 __author__ = 'Ramon Hagenaars'
 __author_email__ = 'ramon.hagenaars@gmail.com'
 __description__ = 'For serializing Python objects to JSON (dicts) and back'
diff --git a/jsons/deserializers/default_string.py b/jsons/deserializers/default_string.py
index 5024198..b20733e 100644
--- a/jsons/deserializers/default_string.py
+++ b/jsons/deserializers/default_string.py
@@ -17,6 +17,9 @@ def default_string_deserializer(obj: str,
     :param kwargs: any keyword arguments.
     :return: the deserialized obj.
     """
+    target_is_str = cls is str and not kwargs.get('_inferred_cls')
+    if target_is_str:
+        return str(obj)
     try:
         result = load(obj, datetime, **kwargs)
     except DeserializationError:


Test patch:
diff --git a/tests/test_str.py b/tests/test_str.py
new file mode 100644
index 0000000..2ec5a35
--- /dev/null
+++ b/tests/test_str.py
@@ -0,0 +1,33 @@
+from datetime import datetime
+from unittest import TestCase
+
+import jsons
+
+
+class TestStr(TestCase):
+    def test_string_is_loaded_as_string(self):
+
+        class C:
+            def __init__(self, x: str):
+                self.x = x
+
+        fork = jsons.fork()
+        jsons.set_deserializer(lambda obj, _, **kwargs: datetime.strptime(obj, '%Y'), datetime, fork_inst=fork)
+        loaded = jsons.load({'x': '1025'}, C, strict=True, fork_inst=fork)
+
+        self.assertIsInstance(loaded.x, str)
+
+    def test_string_is_loaded_as_datetime(self):
+
+        class C:
+            def __init__(self, x):
+                # x has no hint, so the type will be inferred. Since x is not
+                # explicitly targeted as str, it may get parsed as a datetime.
+                # And in this test, it should.
+                self.x = x
+
+        fork = jsons.fork()
+        jsons.set_deserializer(lambda obj, _, **kwargs: datetime.strptime(obj, '%Y'), datetime, fork_inst=fork)
+        loaded = jsons.load({'x': '1025'}, C, strict=True, fork_inst=fork)
+
+        self.assertIsInstance(loaded.x, datetime)