Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve base class support #12

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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