Skip to content

Commit

Permalink
Fix #58 items merging
Browse files Browse the repository at this point in the history
  • Loading branch information
Zac-HD committed Jul 17, 2020
1 parent 42e7d50 commit 45eae99
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 4 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

#### 0.17.3 - 2020-07-17
- improved handling of overlapping `items` keywords (#58)

#### 0.17.2 - 2020-07-16
- improved handling of overlapping `dependencies` keywords (#57)

Expand Down
2 changes: 1 addition & 1 deletion src/hypothesis_jsonschema/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The only public API is `from_schema`; check the docstring for details.
"""

__version__ = "0.17.2"
__version__ = "0.17.3"
__all__ = ["from_schema"]

from ._from_schema import from_schema
41 changes: 38 additions & 3 deletions src/hypothesis_jsonschema/_canonicalise.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
between "I'd like it to be faster" and "doesn't finish at all".
"""

import itertools
import json
import math
import re
Expand Down Expand Up @@ -298,7 +299,7 @@ def canonicalish(schema: JSONType) -> Dict[str, Any]:
elif isinstance(schema.get(key), (bool, dict)):
schema[key] = canonicalish(schema[key])
else:
assert key not in schema
assert key not in schema, (key, schema[key])
for key in SCHEMA_OBJECT_KEYS:
if key in schema:
schema[key] = {
Expand Down Expand Up @@ -831,8 +832,42 @@ def merged(schemas: List[Any]) -> Optional[Schema]:
return None
odeps[k] = m
odeps.update(s.pop("dependencies"))

# TODO: merge `items` schemas or lists-of-schemas
if "items" in out or "items" in s:
oitems = out.pop("items", TRUTHY)
sitems = s.pop("items", TRUTHY)
if isinstance(oitems, list) and isinstance(sitems, list):
out["items"] = []
out["additionalItems"] = merged(
[
out.get("additionalItems", TRUTHY),
s.get("additionalItems", TRUTHY),
]
)
for a, b in itertools.zip_longest(oitems, sitems):
if a is None:
a = out.get("additionalItems", TRUTHY)
elif b is None:
b = s.get("additionalItems", TRUTHY)
out["items"].append(merged([a, b]))
elif isinstance(oitems, list):
out["items"] = [merged([x, sitems]) for x in oitems]
out["additionalItems"] = merged(
[out.get("additionalItems", TRUTHY), sitems]
)
elif isinstance(sitems, list):
out["items"] = [merged([x, oitems]) for x in sitems]
out["additionalItems"] = merged(
[s.get("additionalItems", TRUTHY), oitems]
)
else:
out["items"] = merged([oitems, sitems])
if out["items"] is None:
return None
if isinstance(out["items"], list) and None in out["items"]:
return None
if out.get("additionalItems", TRUTHY) is None:
return None
s.pop("additionalItems", None)

# This loop handles the remaining cases. Notably, we do not attempt to
# merge distinct values for:
Expand Down
19 changes: 19 additions & 0 deletions tests/test_canonicalise.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,25 @@ def test_canonicalises_to_expected(schema, expected):
],
None,
),
([{"items": {"pattern": "a"}}, {"items": {"pattern": "b"}}], None),
([{"items": [{"pattern": "a"}]}, {"items": [{"pattern": "b"}]}], None,),
(
[
{"items": [{}], "additionalItems": {"pattern": "a"}},
{"items": [{}], "additionalItems": {"pattern": "b"}},
],
None,
),
(
[
{"items": [{}, {"type": "string"}], "additionalItems": False},
{"items": [{"type": "string"}]},
],
{
"items": [{"type": "string"}, {"type": "string"}],
"additionalItems": FALSEY,
},
),
]
+ [
([{lo: 0, hi: 9}, {lo: 1, hi: 10}], {lo: 1, hi: 9})
Expand Down

0 comments on commit 45eae99

Please sign in to comment.