Skip to content

Commit f74c176

Browse files
author
Víctor Ruiz
authored
Merge pull request #16 from scrapy-plugins/feature/improve_properties_extraction
Added support for fields allOf, anyOf, oneOf on top level
2 parents 62905d3 + 75e8de5 commit f74c176

File tree

2 files changed

+109
-2
lines changed

2 files changed

+109
-2
lines changed

scrapy_jsonschema/item.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,10 @@ class JsonSchemaMeta(ABCMeta):
5959
JSON_SCHEMA_DRAFT_7: draft7_format_checker,
6060
}
6161

62+
combination_schemas_keywords = ['allOf', 'anyOf', 'oneOf']
63+
6264
def __new__(mcs, class_name, bases, attrs):
6365
cls = super(JsonSchemaMeta, mcs).__new__(mcs, class_name, bases, attrs)
64-
6566
fields = {}
6667
schema = attrs.get('jsonschema', {})
6768
if cls.merge_schema:
@@ -77,7 +78,7 @@ def __new__(mcs, class_name, bases, attrs):
7778
)
7879
cls.validator = cls._get_validator(schema)
7980
cls.validator.check_schema(schema)
80-
for k in schema['properties']:
81+
for k in cls.get_top_level_property_names(schema):
8182
fields[k] = Field()
8283
cls.fields = cls.fields.copy()
8384
cls.fields.update(fields)
@@ -90,6 +91,16 @@ def __new__(mcs, class_name, bases, attrs):
9091
]
9192
return cls
9293

94+
@classmethod
95+
def get_top_level_property_names(cls, schema):
96+
for field in schema.get('properties', {}):
97+
yield field
98+
99+
for keyword in cls.combination_schemas_keywords:
100+
for subschema in schema.get(keyword, []):
101+
for field in subschema.get('properties', {}):
102+
yield field
103+
93104
@classmethod
94105
def _get_validator(cls, schema):
95106
draft_version = schema.get('$schema')

tests/test_item.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,102 @@
1616
merge_schema_new,
1717
)
1818

19+
class SchemaWithCombiningKeywords(TestCase):
20+
21+
schema_allOf = {
22+
"$schema": JSON_SCHEMA_DRAFT_7,
23+
"allOf": [
24+
{
25+
"properties": {"foo": {"type": "string"}},
26+
"required": ["foo"],
27+
},
28+
{
29+
"properties": {"bar": {"type": "number"}},
30+
"required": ["bar"]
31+
}
32+
]
33+
}
34+
35+
schema_anyOf = {
36+
"$schema": JSON_SCHEMA_DRAFT_7,
37+
"anyOf": [
38+
{
39+
"properties": {"foo": {"type": "string"}},
40+
"required": ["foo"],
41+
},
42+
{
43+
"properties": {"bar": {"type": "number"}},
44+
"required": ["bar"]
45+
}
46+
]
47+
}
48+
49+
schema_oneOf = {
50+
"$schema": JSON_SCHEMA_DRAFT_7,
51+
"oneOf": [
52+
{
53+
"properties": {"foo": {"type": "string"}},
54+
"required": ["foo"],
55+
},
56+
{
57+
"properties": {"bar": {"type": "number"}},
58+
"required": ["bar"]
59+
}
60+
]
61+
}
62+
63+
def test_all_of_schema(self):
64+
65+
class allOfItem(JsonSchemaItem):
66+
jsonschema = self.schema_allOf
67+
68+
item = allOfItem()
69+
item['foo'] = 'foo'
70+
item['bar'] = 2
71+
self.assertFalse(list(item.validator.iter_errors(dict(item))))
72+
73+
with pytest.raises(AssertionError):
74+
item = allOfItem()
75+
item['foo'] = 'foo'
76+
self.assertFalse(list(item.validator.iter_errors(dict(item))))
77+
78+
79+
def test_any_of_schema(self):
80+
81+
class anyOfItem(JsonSchemaItem):
82+
jsonschema = self.schema_anyOf
83+
84+
item = anyOfItem()
85+
item['foo'] = 'foo'
86+
item['bar'] = 2
87+
self.assertFalse(list(item.validator.iter_errors(dict(item))))
88+
89+
item = anyOfItem()
90+
item['foo'] = 'foo'
91+
self.assertFalse(list(item.validator.iter_errors(dict(item))))
92+
93+
item = anyOfItem()
94+
item['bar'] = 2
95+
self.assertFalse(list(item.validator.iter_errors(dict(item))))
96+
97+
def test_one_of_schema(self):
98+
99+
class oneOfItem(JsonSchemaItem):
100+
jsonschema = self.schema_oneOf
101+
102+
item = oneOfItem()
103+
item['foo'] = 'foo'
104+
self.assertFalse(list(item.validator.iter_errors(dict(item))))
105+
106+
item = oneOfItem()
107+
item['bar'] = 2
108+
self.assertFalse(list(item.validator.iter_errors(dict(item))))
109+
110+
with pytest.raises(AssertionError):
111+
item = oneOfItem()
112+
item['foo'] = 'foo'
113+
item['bar'] = 2
114+
self.assertFalse(list(item.validator.iter_errors(dict(item))))
19115

20116
class ValidSchemaTestCase(TestCase):
21117

0 commit comments

Comments
 (0)