def test_records_bad_uris_and_keeps_going(self, mocker): from openapi_python_client.parser.properties import Schemas, build_schemas from openapi_python_client.schema import Schema components = { "first": Schema.construct(), "second": Schema.construct() } update_schemas_with_data = mocker.patch( f"{MODULE_NAME}.update_schemas_with_data") parse_reference_path = mocker.patch( f"{MODULE_NAME}.parse_reference_path", side_effect=[PropertyError(detail="some details"), "a_path"]) config = Config() result = build_schemas(components=components, schemas=Schemas(), config=config) parse_reference_path.assert_has_calls([ call("#/components/schemas/first"), call("#/components/schemas/second"), ]) update_schemas_with_data.assert_called_once_with( ref_path="a_path", config=config, data=components["second"], schemas=Schemas(errors=[ PropertyError(detail="some details", data=components["first"]) ]), ) assert result == update_schemas_with_data.return_value
def test_retries_failing_properties_while_making_progress(self, mocker): from openapi_python_client.parser.properties import Schemas, build_schemas from openapi_python_client.schema import Schema components = { "first": Schema.construct(), "second": Schema.construct() } update_schemas_with_data = mocker.patch( f"{MODULE_NAME}.update_schemas_with_data", side_effect=[PropertyError(), Schemas(), PropertyError()]) parse_reference_path = mocker.patch( f"{MODULE_NAME}.parse_reference_path") config = Config() result = build_schemas(components=components, schemas=Schemas(), config=config) parse_reference_path.assert_has_calls([ call("#/components/schemas/first"), call("#/components/schemas/second"), call("#/components/schemas/first"), ]) assert update_schemas_with_data.call_count == 3 assert result.errors == [PropertyError()]
def test_response_from_data_property_error(mocker): from openapi_python_client.parser import responses property_from_data = mocker.patch.object(responses, "property_from_data", return_value=(PropertyError(), Schemas())) data = oai.Response.construct( description="", content={ "application/json": oai.MediaType.construct(media_type_schema="something") }) config = MagicMock() response, schemas = responses.response_from_data(status_code=400, data=data, schemas=Schemas(), parent_name="parent", config=config) assert response == PropertyError() property_from_data.assert_called_once_with(name="response_400", required=True, data="something", schemas=Schemas(), parent_name="parent", config=config)
def test_build_schemas(mocker): build_model_property = mocker.patch(f"{MODULE_NAME}.build_model_property") in_data = {"1": mocker.MagicMock(enum=None), "2": mocker.MagicMock(enum=None), "3": mocker.MagicMock(enum=None)} model_1 = mocker.MagicMock() schemas_1 = mocker.MagicMock() model_2 = mocker.MagicMock() schemas_2 = mocker.MagicMock(errors=[]) error = PropertyError() schemas_3 = mocker.MagicMock() # This loops through one for each, then again to retry the error build_model_property.side_effect = [ (model_1, schemas_1), (model_2, schemas_2), (error, schemas_3), (error, schemas_3), ] from openapi_python_client.parser.properties import Schemas, build_schemas result = build_schemas(components=in_data) build_model_property.assert_has_calls( [ mocker.call(data=in_data["1"], name="1", schemas=Schemas(), required=True, parent_name=None), mocker.call(data=in_data["2"], name="2", schemas=schemas_1, required=True, parent_name=None), mocker.call(data=in_data["3"], name="3", schemas=schemas_2, required=True, parent_name=None), mocker.call(data=in_data["3"], name="3", schemas=schemas_2, required=True, parent_name=None), ] ) # schemas_3 was the last to come back from build_model_property, but it should be ignored because it's an error assert result == schemas_2 assert result.errors == [error]
def test_build_parse_error_on_reference(): from openapi_python_client.parser.openapi import build_schemas ref_schema = oai.Reference.construct() in_data = {"1": ref_schema} result = build_schemas(components=in_data) assert result.errors[0] == PropertyError(data=ref_schema, detail="Reference schemas are not supported.")
def test_skips_references_and_keeps_going(self, mocker): from openapi_python_client.parser.properties import Schemas, build_schemas from openapi_python_client.schema import Reference, Schema components = { "a_ref": Reference.construct(), "a_schema": Schema.construct() } update_schemas_with_data = mocker.patch( f"{MODULE_NAME}.update_schemas_with_data") parse_reference_path = mocker.patch( f"{MODULE_NAME}.parse_reference_path") config = Config() result = build_schemas(components=components, schemas=Schemas(), config=config) # Should not even try to parse a path for the Reference parse_reference_path.assert_called_once_with( "#/components/schemas/a_schema") update_schemas_with_data.assert_called_once_with( ref_path=parse_reference_path.return_value, config=config, data=components["a_schema"], schemas=Schemas(errors=[ PropertyError(detail="Reference schemas are not supported.", data=components["a_ref"]) ]), ) assert result == update_schemas_with_data.return_value
def test_property_from_data_ref_enum_with_invalid_default( self, enum_property_factory): from openapi_python_client.parser.properties import Class, Schemas, property_from_data name = "some_enum" data = oai.Schema.construct( default="x", allOf=[oai.Reference.construct(ref="#/components/schemas/MyEnum")]) existing_enum = enum_property_factory( name="an_enum", default="MyEnum.A", values={ "A": "a", "B": "b" }, class_info=Class(name="MyEnum", module_name="my_enum"), python_name="an_enum", ) schemas = Schemas( classes_by_reference={"/components/schemas/MyEnum": existing_enum}) prop, new_schemas = property_from_data(name=name, required=False, data=data, schemas=schemas, parent_name="", config=Config()) assert schemas == new_schemas assert prop == PropertyError( data=data, detail="x is an invalid default for enum MyEnum")
def test_build_list_property_invalid_items(self, mocker): from openapi_python_client.parser import properties name = "name" required = mocker.MagicMock() data = oai.Schema( type="array", items={}, ) schemas = properties.Schemas() second_schemas = properties.Schemas(errors=["error"]) property_from_data = mocker.patch.object( properties, "property_from_data", return_value=(properties.PropertyError(data="blah"), second_schemas)) config = MagicMock() p, new_schemas = properties.build_list_property(name=name, required=required, data=data, schemas=schemas, parent_name="parent", config=config) assert p == PropertyError( data="blah", detail=f"invalid data in items of array {name}") assert new_schemas == second_schemas assert schemas != new_schemas, "Schema was mutated" property_from_data.assert_called_once_with(name=f"{name}_item", required=True, data=data.items, schemas=schemas, parent_name="parent", config=config)
def test_property_from_data_no_valid_props_in_data(self): from openapi_python_client.parser.errors import PropertyError from openapi_python_client.parser.properties import property_from_data data = oai.Schema() assert property_from_data(name="blah", required=True, data=data) == PropertyError( data=data, detail="Schemas must either have one of enum, anyOf, or type defined." )
def test_property_from_data_invalid_ref(self, mocker): from openapi_python_client.parser.properties import PropertyError, Schemas, property_from_data name = mocker.MagicMock() required = mocker.MagicMock() data = oai.Reference.construct(ref=mocker.MagicMock()) parse_reference_path = mocker.patch( f"{MODULE_NAME}.parse_reference_path", return_value=PropertyError(detail="bad stuff") ) schemas = Schemas() prop, new_schemas = property_from_data( name=name, required=required, data=data, schemas=schemas, parent_name="parent", config=mocker.MagicMock() ) parse_reference_path.assert_called_once_with(data.ref) assert prop == PropertyError(data=data, detail="bad stuff") assert schemas == new_schemas
def test_property_from_data_array_no_items(self, mocker): name = mocker.MagicMock() required = mocker.MagicMock() data = oai.Schema(type="array") from openapi_python_client.parser.properties import property_from_data p = property_from_data(name=name, required=required, data=data) assert p == PropertyError(data=data, detail="type array must have items defined")
def test_property_from_data_validation_error(self, mocker): from openapi_python_client.parser.errors import PropertyError from openapi_python_client.parser.properties import property_from_data mocker.patch(f"{MODULE_NAME}._property_from_data").side_effect = ValidationError() data = oai.Schema() assert property_from_data(name="blah", required=True, data=data) == PropertyError( detail="Failed to validate default value", data=data )
def test_property_from_data_union_bad_type(self, mocker): name = "bad_union" required = mocker.MagicMock() data = oai.Schema(anyOf=[{"type": "garbage"}]) mocker.patch("openapi_python_client.utils.remove_string_escapes", return_value=name) from openapi_python_client.parser.properties import Schemas, property_from_data p, s = property_from_data(name=name, required=required, data=data, schemas=Schemas(), parent_name="parent") assert p == PropertyError(detail=f"Invalid property in union {name}", data=oai.Schema(type="garbage"))
def test_property_from_data_unsupported_type(self, mocker): name = mocker.MagicMock() required = mocker.MagicMock() data = oai.Schema.construct(type=mocker.MagicMock()) from openapi_python_client.parser.errors import PropertyError from openapi_python_client.parser.properties import property_from_data assert property_from_data(name=name, required=required, data=data) == PropertyError( data=data, detail=f"unknown type {data.type}" )
def test_property_from_data_union_bad_type(self, mocker): name = mocker.MagicMock() required = mocker.MagicMock() data = oai.Schema(anyOf=[{}]) mocker.patch("openapi_python_client.utils.remove_string_escapes", return_value=name) from openapi_python_client.parser.properties import property_from_data p = property_from_data(name=name, required=required, data=data) assert p == PropertyError(detail=f"Invalid property in union {name}", data=oai.Schema())
def test_property_from_data_array_invalid_items(self, mocker): name = mocker.MagicMock() required = mocker.MagicMock() data = oai.Schema(type="array", items={},) mocker.patch("openapi_python_client.utils.remove_string_escapes", return_value=name) from openapi_python_client.parser.properties import property_from_data p = property_from_data(name=name, required=required, data=data) assert p == PropertyError(data=oai.Schema(), detail=f"invalid data in items of array {name}")
def test_model_name_conflict(self): from openapi_python_client.parser.properties import Schemas, build_model_property data = oai.Schema.construct() schemas = Schemas(classes_by_name={"OtherModel": None}) err, new_schemas = build_model_property( data=data, name="OtherModel", schemas=schemas, required=True, parent_name=None, config=Config() ) assert new_schemas == schemas assert err == PropertyError(detail='Attempted to generate duplicate models with name "OtherModel"', data=data)
def test_build_enum_property_no_values(): from openapi_python_client.parser.properties import Schemas, build_enum_property data = oai.Schema() schemas = Schemas() err, schemas = build_enum_property( data=data, name="Existing", required=True, schemas=schemas, enum=[], parent_name=None, config=Config() ) assert schemas == schemas assert err == PropertyError(detail="No values provided for Enum", data=data)
def test_build_enum_property_conflict(mocker): from openapi_python_client.parser.properties import Schemas, build_enum_property data = oai.Schema() schemas = Schemas(classes_by_name={"Existing": mocker.MagicMock()}) err, schemas = build_enum_property( data=data, name="Existing", required=True, schemas=schemas, enum=[], parent_name=None, config=Config() ) assert schemas == schemas assert err == PropertyError(detail="Found conflicting enums named Existing with incompatible values.", data=data)
def test_build_enum_property_bad_default(): from openapi_python_client.parser.properties import Schemas, build_enum_property data = oai.Schema(default="B") schemas = Schemas() err, schemas = build_enum_property( data=data, name="Existing", required=True, schemas=schemas, enum=["A"], parent_name=None, config=Config() ) assert schemas == schemas assert err == PropertyError(detail="B is an invalid default for enum Existing", data=data)
def test_datetime_bad_default(self): from openapi_python_client.parser.properties import property_from_data name = "datetime_prop" required = True data = oai.Schema.construct(type="string", schema_format="date-time", nullable=True, default="a") result, _ = property_from_data( name=name, required=required, data=data, schemas=Schemas(), config=Config(), parent_name=None ) assert result == PropertyError(detail="Failed to validate default value", data=data)
def test_build_union_property_invalid_property(self, mocker): name = "bad_union" required = mocker.MagicMock() reference = oai.Reference.construct(ref="#/components/schema/NotExist") data = oai.Schema(anyOf=[reference]) mocker.patch("openapi_python_client.utils.remove_string_escapes", return_value=name) from openapi_python_client.parser.properties import Schemas, build_union_property p, s = build_union_property( name=name, required=required, data=data, schemas=Schemas(), parent_name="parent", config=MagicMock() ) assert p == PropertyError(detail=f"Invalid property in union {name}", data=reference)
def test_property_from_data_validation_error(self, mocker): from openapi_python_client.parser.errors import PropertyError from openapi_python_client.parser.properties import Schemas, property_from_data mocker.patch(f"{MODULE_NAME}._property_from_data").side_effect = ValidationError() schemas = Schemas() data = oai.Schema() err, new_schemas = property_from_data( name="blah", required=True, data=data, schemas=schemas, parent_name="parent", config=MagicMock() ) assert err == PropertyError(detail="Failed to validate default value", data=data) assert new_schemas == schemas
def test_property_from_data_ref_not_found(self, mocker): from openapi_python_client.parser.properties import PropertyError, Schemas, property_from_data data = oai.Reference.construct(ref="a/b/c") parse_reference_path = mocker.patch(f"{MODULE_NAME}.parse_reference_path") schemas = Schemas() prop, new_schemas = property_from_data( name="a_prop", required=False, data=data, schemas=schemas, parent_name="parent", config=mocker.MagicMock() ) parse_reference_path.assert_called_once_with(data.ref) assert prop == PropertyError(data=data, detail="Could not find reference in parsed models or enums") assert schemas == new_schemas
def test_bad_props_return_error(self): from openapi_python_client.parser.properties import Schemas, build_model_property data = oai.Schema( properties={ "bad": oai.Schema(type="not_real"), }, ) schemas = Schemas() err, new_schemas = build_model_property( data=data, name="prop", schemas=schemas, required=True, parent_name=None, config=MagicMock() ) assert new_schemas == schemas assert err == PropertyError(detail="unknown type not_real", data=oai.Schema(type="not_real"))
def test_build_list_property_no_items(self, mocker): from openapi_python_client.parser import properties name = mocker.MagicMock() required = mocker.MagicMock() data = oai.Schema.construct(type="array") property_from_data = mocker.patch.object(properties, "property_from_data") schemas = properties.Schemas() p, new_schemas = properties.build_list_property( name=name, required=required, data=data, schemas=schemas, parent_name="parent", config=MagicMock() ) assert p == PropertyError(data=data, detail="type array must have items defined") assert new_schemas == schemas property_from_data.assert_not_called()
def test_property_from_data_ref_not_found(self, mocker): from openapi_python_client.parser.properties import PropertyError, Schemas, property_from_data name = mocker.MagicMock() required = mocker.MagicMock() data = oai.Reference.construct(ref=mocker.MagicMock()) parse_reference_path = mocker.patch(f"{MODULE_NAME}.parse_reference_path") mocker.patch("openapi_python_client.utils.remove_string_escapes", return_value=name) schemas = Schemas() prop, new_schemas = property_from_data( name=name, required=required, data=data, schemas=schemas, parent_name="parent", config=mocker.MagicMock() ) parse_reference_path.assert_called_once_with(data.ref) assert prop == PropertyError(data=data, detail="Could not find reference in parsed models or enums") assert schemas == new_schemas
def test_bad_additional_props_return_error(self): from openapi_python_client.parser.properties import Config, Schemas, build_model_property additional_properties = oai.Schema( type="object", properties={ "bad": oai.Schema(type="not_real"), }, ) data = oai.Schema(additionalProperties=additional_properties) schemas = Schemas() err, new_schemas = build_model_property( data=data, name="prop", schemas=schemas, required=True, parent_name=None, config=Config() ) assert new_schemas == schemas assert err == PropertyError(detail="unknown type not_real", data=oai.Schema(type="not_real"))
def test_build_model_property_bad_prop(): from openapi_python_client.parser.properties import Schemas, build_model_property data = oai.Schema( properties={ "bad": oai.Schema(type="not_real"), }, ) schemas = Schemas(models={"OtherModel": None}) err, new_schemas = build_model_property( data=data, name="prop", schemas=schemas, required=True, parent_name=None, ) assert new_schemas == schemas assert err == PropertyError(detail="unknown type not_real", data=oai.Schema(type="not_real"))
def test_build_model_property_conflict(): from openapi_python_client.parser.properties import Schemas, build_model_property data = oai.Schema.construct( required=["req"], properties={ "req": oai.Schema.construct(type="string"), "opt": oai.Schema(type="string", format="date-time"), }, nullable=False, ) schemas = Schemas(models={"OtherModel": None}) err, new_schemas = build_model_property( data=data, name="OtherModel", schemas=schemas, required=True, parent_name=None, ) assert new_schemas == schemas assert err == PropertyError(detail='Attempted to generate duplicate models with name "OtherModel"', data=data)