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

Issue:
Support for subclass type specialization
Some guidance on whether this is a good or bad idea, but I'd like to do something like this:

```python
@dataclass
class BaseObject(JsonSchemaMixin):
    field: str

@dataclass
class NarrowedObject(BaseMessage, JsonSchemaMixin):
    field: Literal['staticstr']
```

I've got a very simple patch to do this, a very small change to `_get_fields_uncached` that checks not only the base field name, but also it's type. I'm happy to contribute, unless there is a reason _not_ to do this.



Pull request description:
Fields inherited from a base can now be narrowed.
This is useful if, for example, an inherited object specifies a
string literal in place of the more generic 'str'.

```
Shape(type=str)
Rectangle(type='rect')
Triangle(type='tri')
```

fixes #108

Patch:
diff --git a/dataclasses_jsonschema/__init__.py b/dataclasses_jsonschema/__init__.py
index 994d50b..c13177b 100644
--- a/dataclasses_jsonschema/__init__.py
+++ b/dataclasses_jsonschema/__init__.py
@@ -325,15 +325,15 @@ class JsonSchemaMixin:
             dataclass_bases = [
                 klass for klass in cls.__bases__ if is_dataclass(klass) and issubclass(klass, JsonSchemaMixin)
             ]
-            base_field_names = set()
+            base_fields_types = set()
             for base in dataclass_bases:
-                base_field_names |= {f.name for f in fields(base)}
+                base_fields_types |= {(f.name, f.type) for f in fields(base)}
 
             mapped_fields = []
             type_hints = get_type_hints(cls)
             for f in fields(cls):
                 # Skip internal fields
-                if f.name.startswith("__") or (not base_fields and f.name in base_field_names):
+                if f.name.startswith("__") or (not base_fields and (f.name, f.type) in base_fields_types):
                     continue
                 # Note fields() doesn't resolve forward refs
                 f.type = type_hints[f.name]


Test patch:
diff --git a/tests/test_core.py b/tests/test_core.py
index 4919d13..238722f 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -848,6 +848,49 @@ def test_property_serialisation_all_properties():
     assert Rectangle.json_schema() == expected_schema
 
 
+def test_inherited_field_narrowing():
+    @dataclass
+    class BaseObject(JsonSchemaMixin):
+        """Base"""
+        other: float
+        field: str
+
+    @dataclass
+    class NarrowedObject(BaseObject, JsonSchemaMixin):
+        """Narrowed"""
+        field: Literal['staticstr']
+
+    expected_schema = compose_schema({
+      "allOf": [
+        {
+          "$ref": "#/definitions/BaseObject"
+        },
+        {
+          "type": "object",
+          "required": ["field"],
+          "properties": {
+            "field": {"enum": ["staticstr"]}
+          }
+        }
+      ],
+      "description": "Narrowed",
+      "$schema": "http://json-schema.org/draft-06/schema#",
+      "definitions": {
+        "BaseObject": {
+          "type": "object",
+          "required": ["other", "field"],
+          "properties": {
+            "field": {"type": "string"},
+            "other": {"type": "number"}
+          },
+          "description": "Base"
+        }
+      }
+    })
+
+    assert NarrowedObject.json_schema() == expected_schema
+
+
 def test_unrecognized_enum_value():
     class PetType(Enum):
         CAT = "cat"