Skip to content
This repository has been archived by the owner on Aug 19, 2023. It is now read-only.

Failing with Inheritance of inner classes #139

Open
richard-moss opened this issue Sep 25, 2020 · 0 comments
Open

Failing with Inheritance of inner classes #139

richard-moss opened this issue Sep 25, 2020 · 0 comments

Comments

@richard-moss
Copy link

(in relation to #137 (comment))

The json schema produced by inheriting from a dataclass containing an inner class, and modifying the inner class in the inherited class is incorrect.

In the example below, there is a dataclass Top with an inner dataclass called Inner. If you inherit a new class from Top and add a new element to it's inner class, then the json schema produced doesn't include the new element in the new Inner:

@dataclass
class Top(JsonSchemaMixin):
    
    @dataclass
    class Inner(JsonSchemaMixin):
        a: int
        b: int
            
    x: float
    y: Inner

@dataclass
class TopDerived(Top, JsonSchemaMixin):
    
    @dataclass
    class Inner(Top.Inner, JsonSchemaMixin):
        c: int
            
    y: Inner

typing's get_type_hints correctly identifies that Inner in the derived class is defined in the derived class, and has c: int:

get_type_hints(TopDerived)
-> { 'x': float, 'y': __main__.TopDerived.Inner}
get_type_hints(TopDerived.Inner)
-> {'a': int, 'b': int, 'c': int}

Attempting to instantiate a TopDerived without a c also throws expected exception:

a = TopDerived(x=5, y=TopDerived.Inner(a=5, b=10, c=5))    # OK
a = TopDerived(x=5, y=TopDerived.Inner(a=5, b=10))  # missing 'c' exception

Problem

The schema produced by the above fails to use the new defintion of Inner defined in TopDerived:

TopDerived.json_schema()
{'allOf': [{'$ref': '#/definitions/Top'},
  {'type': 'object',
   'required': ['y'],
   'properties': {'y': {'$ref': '#/definitions/Inner'}}}],
 'description': 'TopDerived(x: float, y: __main__.TopDerived.Inner)',
 '$schema': 'http://json-schema.org/draft-06/schema#',
 'definitions': {'Inner': {'type': 'object',
   'required': ['a', 'b'],
   'properties': {'a': {'type': 'integer'}, 'b': {'type': 'integer'}},
   'description': 'Inner(a: int, b: int)'},
  'Top': {'type': 'object',
   'required': ['x', 'y'],
   'properties': {'x': {'type': 'number'},
    'y': {'$ref': '#/definitions/Inner'}},
   'description': 'Top(x: float, y: __main__.Top.Inner)'}}}

Note* - workaround
Changing the inner class name in the derived class does fix the problem, as the naming isn't then confused:

@dataclass
class Top(JsonSchemaMixin):
    
    @dataclass
    class Inner(JsonSchemaMixin):
        a: int
        b: int
            
    x: float
    y: Inner

@dataclass
class TopDerived(Top, JsonSchemaMixin):
    
    @dataclass
    class InnerNew(Top.Inner, JsonSchemaMixin):
        c: int
            
    y: InnerNew

produces a schema of:

{'allOf': [{'$ref': '#/definitions/Top'},
  {'type': 'object',
   'required': ['y'],
   'properties': {'y': {'$ref': '#/definitions/InnerNew'}}}],
 'description': 'TopDerived(x: float, y: __main__.TopDerived.InnerNew)',
 '$schema': 'http://json-schema.org/draft-06/schema#',
 'definitions': {'InnerNew': {'allOf': [{'$ref': '#/definitions/Inner'},
    {'type': 'object',
     'required': ['c'],
     'properties': {'c': {'type': 'integer'}}}],
   'description': 'InnerNew(a: int, b: int, c: int)'},
  'Inner': {'type': 'object',
   'required': ['a', 'b'],
   'properties': {'a': {'type': 'integer'}, 'b': {'type': 'integer'}},
   'description': 'Inner(a: int, b: int)'},
  'Top': {'type': 'object',
   'required': ['x', 'y'],
   'properties': {'x': {'type': 'number'},
    'y': {'$ref': '#/definitions/Inner'}},
   'description': 'Top(x: float, y: __main__.Top.Inner)'}}}
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant