Skip to content

Commit f06c423

Browse files
committed
Further improvements
1 parent a5f3e4a commit f06c423

File tree

3 files changed

+82
-14
lines changed

3 files changed

+82
-14
lines changed

src/hypothesis_jsonschema/_canonicalise.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ def resolve_all_refs(
580580
)
581581

582582
def is_recursive(reference: str) -> bool:
583-
return reference == "#" or resolver.resolution_scope == reference # type: ignore
583+
return reference == "#" or reference in resolver._scopes_stack # type: ignore
584584

585585
# To avoid infinite recursion, we skip all recursive definitions, and such references will be processed later
586586
# A definition is recursive if it contains a reference to itself or one of its ancestors.
@@ -612,7 +612,9 @@ def is_recursive(reference: str) -> bool:
612612
subschema = schema[key]
613613
assert isinstance(subschema, dict)
614614
schema[key] = {
615-
k: resolve_all_refs(v, resolver=resolver) if isinstance(v, dict) else v
615+
k: resolve_all_refs(deepcopy(v), resolver=resolver)
616+
if isinstance(v, dict)
617+
else v
616618
for k, v in subschema.items()
617619
}
618620
assert isinstance(schema, dict)

src/hypothesis_jsonschema/_from_schema.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def __from_schema(
171171
def _recurse() -> st.SearchStrategy[JSONType]:
172172
_, resolved = resolver.resolve(ref) # type: ignore
173173
return from_schema(
174-
resolved, custom_formats=custom_formats, resolver=resolver
174+
deepcopy(resolved), custom_formats=custom_formats, resolver=resolver
175175
)
176176

177177
return st.deferred(_recurse)
@@ -462,16 +462,14 @@ def array_schema(
462462
if max_size is not None:
463463
max_size -= len(items)
464464

465-
items_strats = [_from_schema_(s) for s in deepcopy(items)]
465+
items_strats = [_from_schema_(s) for s in items]
466466
additional_items_strat = _from_schema_(additional_items)
467467

468468
# If we have a contains schema to satisfy, we try generating from it when
469469
# allowed to do so. We'll skip the None (unmergable / no contains) cases
470470
# below, and let Hypothesis ignore the FALSEY cases for us.
471471
if "contains" in schema:
472-
for i, mrgd in enumerate(
473-
merged([schema["contains"], s]) for s in deepcopy(items)
474-
):
472+
for i, mrgd in enumerate(merged([schema["contains"], s]) for s in items):
475473
if mrgd is not None:
476474
items_strats[i] |= _from_schema_(mrgd)
477475
contains_additional = merged([schema["contains"], additional_items])
@@ -508,10 +506,10 @@ def not_seen(elem: JSONType) -> bool:
508506
st.lists(additional_items_strat, min_size=min_size, max_size=max_size),
509507
)
510508
else:
511-
items_strat = _from_schema_(deepcopy(items))
509+
items_strat = _from_schema_(items)
512510
if "contains" in schema:
513511
contains_strat = _from_schema_(schema["contains"])
514-
if merged([deepcopy(items), schema["contains"]]) != schema["contains"]:
512+
if merged([items, schema["contains"]]) != schema["contains"]:
515513
# We only need this filter if we couldn't merge items in when
516514
# canonicalising. Note that for list-items, above, we just skip
517515
# the mixed generation in this case (because they tend to be
@@ -548,7 +546,7 @@ def object_schema(
548546
return st.builds(dict)
549547
names["type"] = "string"
550548

551-
properties = deepcopy(schema.get("properties", {})) # exact name: value schema
549+
properties = schema.get("properties", {}) # exact name: value schema
552550
patterns = schema.get("patternProperties", {}) # regex for names: value schema
553551
# schema for other values; handled specially if nothing matches
554552
additional = schema.get("additionalProperties", {})
@@ -609,7 +607,7 @@ def from_object_schema(draw: Any) -> Any:
609607
if re.search(rgx, string=key) is not None
610608
]
611609
if key in properties:
612-
pattern_schemas.insert(0, deepcopy(properties[key]))
610+
pattern_schemas.insert(0, properties[key])
613611

614612
if pattern_schemas:
615613
out[key] = draw(
@@ -618,9 +616,7 @@ def from_object_schema(draw: Any) -> Any:
618616
else:
619617
out[key] = draw(
620618
from_schema(
621-
deepcopy(additional),
622-
custom_formats=custom_formats,
623-
resolver=resolver,
619+
additional, custom_formats=custom_formats, resolver=resolver,
624620
)
625621
)
626622

tests/test_from_schema.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,9 +452,79 @@ def test_allowed_unknown_custom_format(string):
452452
},
453453
"$ref": "#/definitions/Node",
454454
},
455+
# Simplified Open API schema
456+
{
457+
"type": "object",
458+
"required": ["paths"],
459+
"properties": {"paths": {"$ref": "#/definitions/Paths"}},
460+
"additionalProperties": False,
461+
"definitions": {
462+
"Schema": {
463+
"type": "object",
464+
"properties": {"items": {"$ref": "#/definitions/Schema"}},
465+
"additionalProperties": False,
466+
},
467+
"MediaType": {
468+
"type": "object",
469+
"properties": {"schema": {"$ref": "#/definitions/Schema"}},
470+
"patternProperties": {"^x-": {}},
471+
"additionalProperties": False,
472+
},
473+
"Paths": {
474+
"type": "object",
475+
"patternProperties": {
476+
"^\\/": {"$ref": "#/definitions/PathItem"},
477+
"^x-": {},
478+
},
479+
"additionalProperties": False,
480+
},
481+
"PathItem": {
482+
"type": "object",
483+
"properties": {
484+
"parameters": {
485+
"type": "array",
486+
"items": {"$ref": "#/definitions/Parameter"},
487+
"uniqueItems": True,
488+
},
489+
},
490+
"patternProperties": {
491+
"^(get|put|post|delete|options|head|patch|trace)$": {
492+
"$ref": "#/definitions/Operation"
493+
},
494+
"^x-": {},
495+
},
496+
"additionalProperties": False,
497+
},
498+
"Operation": {
499+
"type": "object",
500+
"required": ["responses"],
501+
"properties": {
502+
"parameters": {
503+
"type": "array",
504+
"items": {"$ref": "#/definitions/Parameter"},
505+
"uniqueItems": True,
506+
},
507+
},
508+
"additionalProperties": False,
509+
},
510+
"Parameter": {
511+
"type": "object",
512+
"properties": {
513+
"schema": {"$ref": "#/definitions/Schema"},
514+
"content": {
515+
"type": "object",
516+
"minProperties": 1,
517+
"maxProperties": 1,
518+
},
519+
},
520+
"additionalProperties": False,
521+
},
522+
},
523+
},
455524
),
456525
)
457526
@given(data=st.data())
527+
@settings(suppress_health_check=[HealthCheck.too_slow, HealthCheck.filter_too_much])
458528
def test_recursive_reference(data, schema):
459529
value = data.draw(from_schema(schema))
460530
jsonschema.validate(value, schema)

0 commit comments

Comments
 (0)