Repository: s-knibbs/dataclasses-jsonschema (python)

Issue:
NewType field encoder not called when converting to dataclass
Custom field encoders for `NewType` fields are not called in `from_dict` due to the order in which the type conditionals are tested.

Instead, the generic behaviour is used which will perform the conversion based on the supertype.

Pull request:
Fix conditional ordering to handle newtype fields correctly
Fixes #115 

Patch:
diff --git a/dataclasses_jsonschema/__init__.py b/dataclasses_jsonschema/__init__.py
index cd9f81f..58fe500 100644
--- a/dataclasses_jsonschema/__init__.py
+++ b/dataclasses_jsonschema/__init__.py
@@ -430,13 +430,13 @@ class JsonSchemaMixin:
             elif field_type_name == "Tuple":
                 def decoder(f, ft, val):
                     return tuple(cls._decode_field(f, ft.__args__[idx], v) for idx, v in enumerate(val))
+            elif field_type in cls._field_encoders:
+                def decoder(_, ft, val): return cls._field_encoders[ft].to_python(val)
             elif hasattr(field_type, "__supertype__"):  # NewType field
                 def decoder(f, ft, val):
                     return cls._decode_field(f, ft.__supertype__, val)
             elif is_enum(field_type):
                 def decoder(_, ft, val): return ft(val)
-            elif field_type in cls._field_encoders:
-                def decoder(_, ft, val): return cls._field_encoders[ft].to_python(val)
             elif field_type == Any:
                 def decoder(_, __, val): return val
             if decoder is None:


Test patch:
diff --git a/tests/test_core.py b/tests/test_core.py
index 0473651..6f31218 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -4,16 +4,16 @@ from enum import Enum
 
 from dataclasses import dataclass, field
 from ipaddress import IPv4Address, IPv6Address
-from typing import List, NewType, Optional, Union, Set, Any
+from typing import List, NewType, Optional, Union, Set, Any, cast
 from typing_extensions import Final, Literal
 from uuid import UUID
 
-from dataclasses_jsonschema.type_defs import Nullable, NULL
+from dataclasses_jsonschema.type_defs import Nullable, NULL, JsonDict
 from .conftest import Foo, Point, Recursive, OpaqueData, ShoppingCart, Product, ProductList, SubSchemas, Bar, Weekday, \
     JsonSchemaMixin, Zoo, Baz
 import pytest
 
-from dataclasses_jsonschema import SchemaType, ValidationError, DecimalField, JsonSchemaMeta
+from dataclasses_jsonschema import SchemaType, ValidationError, DecimalField, JsonSchemaMeta, FieldEncoder
 
 FOO_SCHEMA = {
     'description': 'A foo that foos',
@@ -916,3 +916,26 @@ def test_inheritance_and_additional_properties_disallowed():
         @dataclass
         class Cat(Pet, allow_additional_props=False):
             hunting_skill: str
+
+
+def test_newtype_decoding():
+    StrippedString = NewType('StrippedString', str)
+
+    class StrippedStringField(FieldEncoder[StrippedString, str]):
+
+        def to_python(self, value: str) -> StrippedString:
+            return cast(StrippedString, value.strip())
+
+        @property
+        def json_schema(self) -> JsonDict:
+            return {'type': 'string'}
+
+    JsonSchemaMixin.register_field_encoders({StrippedString: StrippedStringField()})
+
+    @dataclass
+    class Pet(JsonSchemaMixin):
+        name: StrippedString
+        type: str
+
+    p = Pet.from_dict({'name': '  Fido ', 'type': 'dog'})
+    assert p.name == 'Fido'