Skip to content
Open
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
1 change: 1 addition & 0 deletions news/2037.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix crash in JSON schema providers for Dict and List fields when sub-types are missing by making adapter lookups safe.
34 changes: 34 additions & 0 deletions src/plone/restapi/tests/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -797,3 +797,37 @@ def test_jsonfield(self):
},
adapter.get_schema(),
)

def test_dict_without_types(self):
field = schema.Dict(title="My field", description="My great field")
adapter = getMultiAdapter(
(field, self.portal, self.request), IJsonSchemaProvider
)
# This currently crashes with ComponentLookupError
self.assertEqual(
{
"type": "dict",
"title": "My field",
"description": "My great field",
},
adapter.get_schema(),
)

def test_list_without_value_type(self):
field = schema.List(title="My field", description="My great field")
adapter = getMultiAdapter(
(field, self.portal, self.request), IJsonSchemaProvider
)
# This currently crashes with ComponentLookupError
self.assertEqual(
{
"type": "array",
"title": "My field",
"description": "My great field",
"factory": "List",
"uniqueItems": False,
"additionalItems": True,
"items": {},
},
adapter.get_schema(),
)
55 changes: 35 additions & 20 deletions src/plone/restapi/types/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from plone.schema import IJSONField
from z3c.formwidget.query.interfaces import IQuerySource
from zope.component import adapter
from zope.component import getMultiAdapter
from zope.component import queryMultiAdapter
from zope.i18n import translate
from zope.interface import implementer
from zope.interface import Interface
Expand Down Expand Up @@ -270,11 +270,16 @@ def get_factory(self):

def get_items(self):
"""Get items properties."""
value_type_adapter = getMultiAdapter(
(self.field.value_type, self.context, self.request), IJsonSchemaProvider
)

return value_type_adapter.get_schema()
if self.field.value_type:
value_type_adapter = queryMultiAdapter(
(self.field.value_type, self.context, self.request), IJsonSchemaProvider
)
if value_type_adapter:
try:
return value_type_adapter.get_schema()
except NotImplementedError:
pass
return {}

def additional(self):
info = {}
Expand Down Expand Up @@ -434,20 +439,30 @@ def get_type(self):

def additional(self):
info = {}
key_type = getMultiAdapter(
(self.field.key_type, self.context, self.request), IJsonSchemaProvider
)
info["key_type"] = {
"schema": key_type.get_schema(),
"additional": key_type.additional(),
}
value_type = getMultiAdapter(
(self.field.value_type, self.context, self.request), IJsonSchemaProvider
)
info["value_type"] = {
"schema": value_type.get_schema(),
"additional": value_type.additional(),
}
if self.field.key_type:
key_type = queryMultiAdapter(
(self.field.key_type, self.context, self.request), IJsonSchemaProvider
)
if key_type:
try:
info["key_type"] = {
"schema": key_type.get_schema(),
"additional": key_type.additional(),
}
except NotImplementedError:
pass
if self.field.value_type:
value_type = queryMultiAdapter(
(self.field.value_type, self.context, self.request), IJsonSchemaProvider
)
if value_type:
try:
info["value_type"] = {
"schema": value_type.get_schema(),
"additional": value_type.additional(),
}
except NotImplementedError:
pass
return info


Expand Down