diff --git a/bravado_core/model.py b/bravado_core/model.py index ca6b615f..a662fbcf 100644 --- a/bravado_core/model.py +++ b/bravado_core/model.py @@ -770,28 +770,63 @@ def descend(fragment, json_reference=None): def _run_post_processing(spec): visited_models = {} - # Discover all the models - _post_process_spec( - spec_dict=spec.spec_dict, - spec_resolver=spec.resolver, - on_container_callbacks=[ - functools.partial( - _tag_models, - visited_models=visited_models, - swagger_spec=spec, - ), - functools.partial( - _bless_models, - visited_models=visited_models, - swagger_spec=spec, - ), - functools.partial( - _collect_models, - models=spec.definitions, - swagger_spec=spec, - ), - ], - ) + + def _call_post_process_spec(spec_dict): + # Discover all the models in spec_dict + _post_process_spec( + spec_dict=spec_dict, + spec_resolver=spec.resolver, + on_container_callbacks=[ + functools.partial( + _tag_models, + visited_models=visited_models, + swagger_spec=spec, + ), + functools.partial( + _bless_models, + visited_models=visited_models, + swagger_spec=spec, + ), + functools.partial( + _collect_models, + models=spec.definitions, + swagger_spec=spec, + ), + ], + ) + + # Post process specs to identify models + _call_post_process_spec(spec.spec_dict) + + processed_uris = { + uri + for uri in spec.resolver.store + if uri == spec.origin_url or re.match(r'http://json-schema.org/draft-\d+/schema', uri) + } + additional_uri = _get_unprocessed_uri(spec, processed_uris) + while additional_uri: + # Post process each referenced specs to identify models in definitions of linked files + with spec.resolver.in_scope(additional_uri): + _call_post_process_spec( + spec.resolver.store[additional_uri], + ) + + processed_uris.add(additional_uri) + additional_uri = _get_unprocessed_uri(spec, processed_uris) + + +def _get_unprocessed_uri(swagger_spec, processed_uris): + """ + Retrieve an un-process URI from swagger spec referred URIs + + :type swagger_spec: bravado_core.spec.Spec + :param processed_uris: URIs of the already processed URIs + + :rtype: str + """ + for uri in swagger_spec.resolver.store: + if uri not in processed_uris: + return uri def model_discovery(swagger_spec): diff --git a/test-data/2.0/multi-file-recursive/aux.json b/test-data/2.0/multi-file-recursive/aux.json index 8c08cc2e..fbf9f02f 100644 --- a/test-data/2.0/multi-file-recursive/aux.json +++ b/test-data/2.0/multi-file-recursive/aux.json @@ -17,6 +17,11 @@ }, "not_used_remote_reference": { "type": "object", + "properties": { + "random_number": { + "$ref": "aux_2.json#/definitions/random_integer" + } + }, "x-model": "not_used_remote_reference" } }, diff --git a/test-data/2.0/multi-file-recursive/aux_2.json b/test-data/2.0/multi-file-recursive/aux_2.json new file mode 100644 index 00000000..09a7381f --- /dev/null +++ b/test-data/2.0/multi-file-recursive/aux_2.json @@ -0,0 +1,21 @@ +{ + "definitions": { + "not_referenced_models_in_not_direcly_linked_file": { + "type": "object" + }, + "random_integer": { + "type": "object", + "properties": { + "value": { + "type": "integer" + }, + "min-value": { + "type": "integer" + }, + "max-value": { + "type": "integer" + } + } + } + } +} diff --git a/test-data/2.0/multi-file-recursive/flattened-multi-file-recursive-spec.json b/test-data/2.0/multi-file-recursive/flattened-multi-file-recursive-spec.json index b4b4129b..c4140d15 100644 --- a/test-data/2.0/multi-file-recursive/flattened-multi-file-recursive-spec.json +++ b/test-data/2.0/multi-file-recursive/flattened-multi-file-recursive-spec.json @@ -1,6 +1,11 @@ { "definitions": { "lfile:aux.json|..definitions..not_used_remote_reference": { + "properties": { + "random_number": { + "$ref": "#/definitions/lfile:aux_2.json|..definitions..random_integer" + } + }, "type": "object", "x-model": "not_used_remote_reference" }, @@ -19,6 +24,25 @@ "type": "object", "x-model": "ping" }, + "lfile:aux_2.json|..definitions..not_referenced_models_in_not_direcly_linked_file": { + "type": "object", + "x-model": "not_referenced_models_in_not_direcly_linked_file" + }, + "lfile:aux_2.json|..definitions..random_integer": { + "properties": { + "max-value": { + "type": "integer" + }, + "min-value": { + "type": "integer" + }, + "value": { + "type": "integer" + } + }, + "type": "object", + "x-model": "random_integer" + }, "lfile:swagger.json|..definitions..model_with_allOf_recursive": { "allOf": [ { @@ -39,11 +63,6 @@ "x-model": "model_with_allOf_recursive" }, "lfile:swagger.json|..definitions..not_used": { - "properties": { - "not_used_remote_reference": { - "$ref": "#/definitions/lfile:aux.json|..definitions..not_used_remote_reference" - } - }, "type": "object", "x-model": "not_used" }, diff --git a/test-data/2.0/multi-file-recursive/swagger.json b/test-data/2.0/multi-file-recursive/swagger.json index 8e920597..adb7a834 100644 --- a/test-data/2.0/multi-file-recursive/swagger.json +++ b/test-data/2.0/multi-file-recursive/swagger.json @@ -21,11 +21,6 @@ }, "not_used": { "type": "object", - "properties": { - "not_used_remote_reference": { - "$ref": "aux.json#/definitions/not_used_remote_reference" - } - }, "x-model": "not_used" }, "pong": { diff --git a/test-data/2.0/multi-file-specs-with-no-x-model/flattened-multi-file-with-no-xmodel.json b/test-data/2.0/multi-file-specs-with-no-x-model/flattened-multi-file-with-no-xmodel.json index 07d4e1e4..62b17b74 100644 --- a/test-data/2.0/multi-file-specs-with-no-x-model/flattened-multi-file-with-no-xmodel.json +++ b/test-data/2.0/multi-file-specs-with-no-x-model/flattened-multi-file-with-no-xmodel.json @@ -2,7 +2,7 @@ "definitions": { "lfile:aux.json|..definitions..referenced_object": { "type": "object", - "x-model": "lfile:aux.json|..definitions..referenced_object" + "x-model": "referenced_object" }, "lfile:swagger.json|..definitions..object": { "properties": { diff --git a/tests/model/collect_models_test.py b/tests/model/collect_models_test.py index 90fc8442..4cfe6260 100644 --- a/tests/model/collect_models_test.py +++ b/tests/model/collect_models_test.py @@ -19,18 +19,22 @@ def pet_model_spec(): } -def test_simple(minimal_swagger_dict, pet_model_spec): +@pytest.mark.parametrize( + 'origin_url', [None, 'origin_url'], +) +def test_simple(minimal_swagger_dict, pet_model_spec, origin_url): minimal_swagger_dict['definitions']['Pet'] = pet_model_spec - swagger_spec = Spec(minimal_swagger_dict) + swagger_spec = Spec(minimal_swagger_dict, origin_url=origin_url) models = {} + json_reference = '{}#/definitions/Pet'.format(origin_url or '') _collect_models( minimal_swagger_dict['definitions']['Pet'], models=models, swagger_spec=swagger_spec, - json_reference='#/definitions/Pet/x-model', + json_reference=json_reference + '/x-model', ) assert 'Pet' in models - assert models['Pet']._json_reference == '#/definitions/Pet' + assert models['Pet']._json_reference == json_reference def test_no_model_type_generation_for_not_object_type(minimal_swagger_dict):