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

Issue:
Improve handling of enum fields in `from_object`
We should automatically convert enum fields from the source field by calling the enum constructor.

The enum constructor accepts both enums and enum values.

Pull request description:
Improve enum handling in `from_object`
Add return type annotation for `from_object`

Fixes #84

Patch:
diff --git a/dataclasses_jsonschema/__init__.py b/dataclasses_jsonschema/__init__.py
index 92bbf2e..3c01cc8 100644
--- a/dataclasses_jsonschema/__init__.py
+++ b/dataclasses_jsonschema/__init__.py
@@ -409,7 +409,7 @@ class JsonSchemaMixin:
         return instance
 
     @classmethod
-    def from_object(cls: Type[T], obj: Any, exclude: FieldExcludeList = tuple()):
+    def from_object(cls: Type[T], obj: Any, exclude: FieldExcludeList = tuple()) -> T:
         """Returns a dataclass instance from another object (typically an ORM model).
         The `exclude` parameter is a tuple of field names or (field.name, nested_exclude)
         to exclude from the conversion. For example `exclude=('artist_name', ('albums', ('tracks',))` will exclude
@@ -434,6 +434,8 @@ class JsonSchemaMixin:
             field_type_name = cls._get_field_type_name(ft)
             if cls._is_json_schema_subclass(ft):
                 values[field.name] = ft.from_object(getattr(obj, field.name), exclude=sub_exclude)
+            elif is_enum(ft):
+                values[field.name] = ft(getattr(obj, field.name))
             elif field_type_name == "List" and cls._is_json_schema_subclass(ft.__args__[0]):
                 values[field.name] = [
                     ft.__args__[0].from_object(v, exclude=sub_exclude) for v in getattr(obj, field.name)


Test patch:
diff --git a/tests/test_core.py b/tests/test_core.py
index 977660a..55cd03b 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -1,5 +1,7 @@
 import datetime
 from _decimal import Decimal
+from enum import Enum
+
 from dataclasses import dataclass, field
 from ipaddress import IPv4Address, IPv6Address
 from typing import List, NewType, Optional, Union
@@ -453,6 +455,11 @@ def test_literal_types():
 
 def test_from_object():
 
+    class Genre(Enum):
+        HORROR = "horror"
+        BIOGRAPHY = "biography"
+        THRILLER = "thriller"
+
     class AuthorModel:
 
         def __init__(self, name, age, books):
@@ -462,15 +469,17 @@ def test_from_object():
 
     class BookModel:
 
-        def __init__(self, name, first_print, publisher):
+        def __init__(self, name, first_print, publisher, genre):
             self.name = name
             self.first_print = first_print
             self.publisher = publisher
+            self.genre = genre
 
     @dataclass
     class Book(JsonSchemaMixin):
         name: str
         publisher: str
+        genre: Genre
         first_print: Optional[datetime.datetime] = None
 
     @dataclass
@@ -479,8 +488,10 @@ def test_from_object():
         age: Optional[int] = None
         books: Optional[List[Book]] = None
 
-    sample_author = AuthorModel("Joe Bloggs", 32, [BookModel("Hello World!", datetime.datetime.utcnow(), "ACME Corp")])
-    expected_author = Author("Joe Bloggs", books=[Book("Hello World!", "ACME Corp")])
+    sample_author = AuthorModel(
+        "Joe Bloggs", 32, [BookModel("Hello World!", datetime.datetime.utcnow(), "ACME Corp", "biography")]
+    )
+    expected_author = Author("Joe Bloggs", books=[Book("Hello World!", "ACME Corp", Genre.BIOGRAPHY)])
     assert Author.from_object(sample_author, exclude=('age', ('books', ('first_print',)))) == expected_author
 
     with pytest.raises(ValueError):