Skip to content

Commit

Permalink
Improve base class support (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
BenjaminPelletier authored Nov 9, 2023
1 parent 0de8a73 commit a137d9e
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/implicitdict/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ def _parse_value(value, value_type: Type):
# value is an ImplicitDict
return ImplicitDict.parse(value, value_type)

if hasattr(value_type, "__orig_bases__") and value_type.__orig_bases__:
return value_type(_parse_value(value, value_type.__orig_bases__[0]))

else:
# value is a non-generic type that is not an ImplicitDict
return value_type(value) if value_type else value
Expand Down
3 changes: 3 additions & 0 deletions src/implicitdict/jsonschema.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ def _schema_for(value_type: Type, schema_vars_resolver: SchemaVarsResolver, sche
if value_type == dict or issubclass(value_type, dict):
return {"type": "object"}, False

if hasattr(value_type, "__orig_bases__") and value_type.__orig_bases__:
return _schema_for(value_type.__orig_bases__[0], schema_vars_resolver, schema_repository, context)

raise NotImplementedError(f"Automatic JSON schema generation for {value_type} type is not yet implemented")


Expand Down
18 changes: 17 additions & 1 deletion tests/test_inheritance.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

from implicitdict import ImplicitDict

from .test_types import InheritanceData, MySubclass
from .test_types import InheritanceData, MySubclass, SpecialSubclassesContainer, SpecialListClass, MySpecialClass, \
SpecialComplexListClass


def test_inheritance():
Expand Down Expand Up @@ -49,3 +50,18 @@ def test_inheritance():
assert subclass2.buzz == "burrs"
assert subclass.has_default_baseclass == "In MyData 3"
assert subclass.has_default_subclass == "In MySubclass 3"


def test_inherited_classes():
data: SpecialSubclassesContainer = SpecialSubclassesContainer.example_value()
assert isinstance(data.special_list, SpecialListClass)
assert data.special_list.hello() == "SpecialListClass"
for item in data.special_list:
assert isinstance(item, MySpecialClass)
assert item.is_special

assert isinstance(data.special_complex_list, SpecialComplexListClass)
assert data.special_complex_list.hello() == "SpecialComplexListClass"
for item in data.special_complex_list:
assert isinstance(item, MySubclass)
assert item.hello() == "MySubclass"
13 changes: 12 additions & 1 deletion tests/test_jsonschema.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
from implicitdict import ImplicitDict
import jsonschema

from .test_types import ContainerData, InheritanceData, NestedDefinitionsData, NormalUsageData, OptionalData, PropertiesData, SpecialTypesData
from .test_types import ContainerData, InheritanceData, NestedDefinitionsData, NormalUsageData, OptionalData, \
PropertiesData, SpecialTypesData, SpecialSubclassesContainer


def _resolver(t: Type) -> SchemaVars:
Expand Down Expand Up @@ -72,6 +73,16 @@ def test_inheritance():
data = InheritanceData.example_value()
_verify_schema_validation(data, InheritanceData)

data = SpecialSubclassesContainer.example_value()
_verify_schema_validation(data, SpecialSubclassesContainer)
repo = {}
implicitdict.jsonschema.make_json_schema(SpecialSubclassesContainer, _resolver, repo)
name = _resolver(SpecialSubclassesContainer).name
schema = repo[name]
props = schema["properties"]
assert "special_list" in props
assert "special_complex_list" in props


def test_optional():
for data in OptionalData.example_values().values():
Expand Down
19 changes: 19 additions & 0 deletions tests/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,25 @@ def hello(self) -> str:
return "MySubclass"


class SpecialListClass(List[MySpecialClass]):
def hello(self) -> str:
return "SpecialListClass"


class SpecialComplexListClass(List[MySubclass]):
def hello(self) -> str:
return "SpecialComplexListClass"


class SpecialSubclassesContainer(ImplicitDict):
special_list: SpecialListClass
special_complex_list: SpecialComplexListClass

@staticmethod
def example_value():
return ImplicitDict.parse({'special_list': ['foo'], 'special_complex_list': [{'foo': 'oof'}]}, SpecialSubclassesContainer)


class MutabilityData(ImplicitDict):
primitive: str
list_of_primitives: List[str]
Expand Down

0 comments on commit a137d9e

Please sign in to comment.