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_conflicting_properties_same_types(self, model_property_factory, string_property_factory): from openapi_python_client.parser.properties import Schemas from openapi_python_client.parser.properties.model_property import _process_properties data = oai.Schema.construct(allOf=[ oai.Reference.construct(ref="#/First"), oai.Reference.construct(ref="#/Second") ]) schemas = Schemas( classes_by_reference={ "/First": model_property_factory(optional_properties=[ string_property_factory(default="abc") ]), "/Second": model_property_factory( optional_properties=[string_property_factory()]), }) result = _process_properties(data=data, schemas=schemas, class_name="", config=Config()) assert isinstance(result, PropertyError)
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_property_from_data_ref_enum(self, enum_property_factory): from openapi_python_client.parser.properties import Class, Schemas, property_from_data name = "some_enum" data = oai.Reference.construct(ref="#/components/schemas/MyEnum") existing_enum = enum_property_factory( name="an_enum", required=False, values={"A": "a"}, class_info=Class(name="MyEnum", module_name="my_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 prop == enum_property_factory( name="some_enum", required=False, values={"A": "a"}, class_info=Class(name="MyEnum", module_name="my_enum"), ) assert schemas == new_schemas
def test_allof_int_enums(self, model_property_factory, enum_property_factory): from openapi_python_client.parser.properties import Schemas from openapi_python_client.parser.properties.model_property import _process_properties data = oai.Schema.construct(allOf=[ oai.Reference.construct(ref="#/First"), oai.Reference.construct(ref="#/Second") ]) enum_property1 = enum_property_factory( name="an_enum", values={ "foo": 1, "bar": 2 }, value_type=int, ) enum_property2 = enum_property_factory( name="an_enum", values={"foo": 1}, value_type=int, ) schemas = Schemas( classes_by_reference={ "/First": model_property_factory(optional_properties=[enum_property1]), "/Second": model_property_factory(optional_properties=[enum_property2]), }) result = _process_properties(data=data, schemas=schemas, class_name="", config=Config()) assert result.required_props[0] == enum_property2
def test_property_from_data_ref_model(self, model_property_factory): from openapi_python_client.parser.properties import Class, ModelProperty, Schemas, property_from_data name = "new_name" required = False class_name = "MyModel" data = oai.Reference.construct( ref=f"#/components/schemas/{class_name}") class_info = Class(name=class_name, module_name="my_model") existing_model = model_property_factory( name="old_name", class_info=class_info, ) schemas = Schemas(classes_by_reference={ f"/components/schemas/{class_name}": existing_model }) prop, new_schemas = property_from_data(name=name, required=required, data=data, schemas=schemas, parent_name="", config=Config()) assert prop == model_property_factory( name=name, required=required, class_info=class_info, ) assert schemas == new_schemas
def test_allof_enum_incompatible_type(self, model_property_factory, enum_property_factory, int_property_factory): from openapi_python_client.parser.properties import Schemas from openapi_python_client.parser.properties.model_property import _process_properties data = oai.Schema.construct(allOf=[ oai.Reference.construct(ref="#/First"), oai.Reference.construct(ref="#/Second") ]) enum_property = enum_property_factory( values={"foo": 1}, value_type=str, ) schemas = Schemas( classes_by_reference={ "/First": model_property_factory( optional_properties=[int_property_factory()]), "/Second": model_property_factory(optional_properties=[enum_property]), }) result = _process_properties(data=data, schemas=schemas, class_name="", config=Config()) assert isinstance(result, PropertyError)
def test_allof_string_enum_and_string(self, model_property_factory, enum_property_factory, string_property_factory): from openapi_python_client.parser.properties import Schemas from openapi_python_client.parser.properties.model_property import _process_properties data = oai.Schema.construct(allOf=[ oai.Reference.construct(ref="#/First"), oai.Reference.construct(ref="#/Second") ]) enum_property = enum_property_factory( required=False, nullable=True, values={"foo": "foo"}, ) schemas = Schemas( classes_by_reference={ "/First": model_property_factory(optional_properties=[enum_property]), "/Second": model_property_factory(optional_properties=[ string_property_factory(required=False, nullable=True) ]), }) result = _process_properties(data=data, schemas=schemas, class_name="", config=Config()) assert result.optional_props[0] == enum_property
def test_property_from_data_union_of_one_element(self, mocker, model_property_factory): from openapi_python_client.parser.properties import Class, ModelProperty, Schemas, property_from_data name = "new_name" required = False class_name = "MyModel" nullable = True existing_model = model_property_factory() schemas = Schemas( classes_by_reference={f"/{class_name}": existing_model}) data = oai.Schema.construct( allOf=[oai.Reference.construct(ref=f"#/{class_name}")], nullable=nullable, ) build_union_property = mocker.patch( f"{MODULE_NAME}.build_union_property") prop, schemas = property_from_data(name=name, required=required, data=data, schemas=schemas, parent_name="parent", config=Config()) assert prop == attr.evolve(existing_model, name=name, required=required, nullable=nullable, python_name=name) build_union_property.assert_not_called()
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_happy_path(self, model_property_factory, string_property_factory, date_time_property_factory): from openapi_python_client.parser.properties import Class, Schemas, build_model_property name = "prop" nullable = False required = True data = oai.Schema.construct( required=["req"], title="MyModel", properties={ "req": oai.Schema.construct(type="string"), "opt": oai.Schema(type="string", format="date-time"), }, description="A class called MyModel", nullable=nullable, ) schemas = Schemas(classes_by_reference={"OtherModel": None}, classes_by_name={"OtherModel": None}) model, new_schemas = build_model_property(data=data, name=name, schemas=schemas, required=required, parent_name="parent", config=Config()) assert new_schemas != schemas assert new_schemas.classes_by_name == { "OtherModel": None, "ParentMyModel": model, } assert new_schemas.classes_by_reference == { "OtherModel": None, } assert model == model_property_factory( name=name, required=required, nullable=nullable, class_info=Class(name="ParentMyModel", module_name="parent_my_model"), required_properties=[ string_property_factory(name="req", required=True) ], optional_properties=[ date_time_property_factory(name="opt", required=False) ], description=data.description, relative_imports={ "from dateutil.parser import isoparse", "from typing import cast", "import datetime", "from ..types import UNSET, Unset", "from typing import Union", }, additional_properties=True, )
def test_class_from_string_default_config(): from openapi_python_client import Config from openapi_python_client.parser.properties import Class class_ = Class.from_string(string="#/components/schemas/PingResponse", config=Config()) assert class_.name == "PingResponse" assert class_.module_name == "ping_response"
def test__string_based_property_binary_format(self, file_property_factory): from openapi_python_client.parser.properties import property_from_data name = "file_prop" required = True nullable = True data = oai.Schema.construct(type="string", schema_format="binary", nullable=nullable, default="a") p, _ = property_from_data( name=name, required=required, data=data, schemas=Schemas(), config=Config(), parent_name=None ) assert p == file_property_factory(name=name, required=required, nullable=nullable)
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_custom_templates(mocker): from openapi_python_client import GeneratorData, MetaType, Project openapi = mocker.MagicMock( autospec=GeneratorData, title="My Test API", ) project = Project(openapi=openapi, meta=MetaType.POETRY, config=Config()) assert isinstance(project.env.loader, jinja2.PackageLoader) project = Project( openapi=openapi, custom_template_path="../end_to_end_tests/test_custom_templates", meta=MetaType.POETRY, config=Config(), ) assert isinstance(project.env.loader, jinja2.ChoiceLoader) assert len(project.env.loader.loaders) == 2 assert isinstance(project.env.loader.loaders[0], jinja2.FileSystemLoader) assert isinstance(project.env.loader.loaders[1], jinja2.PackageLoader)
def test___init___no_meta(self, mocker): openapi = mocker.MagicMock(title="My Test API") from openapi_python_client import MetaType, Project project = Project(openapi=openapi, meta=MetaType.NONE, config=Config()) assert project.openapi == openapi assert project.package_description == "A client library for accessing My Test API" assert project.meta == MetaType.NONE assert project.project_dir == pathlib.Path.cwd() assert project.package_dir == pathlib.Path.cwd() / project.package_name
def test__string_based_property_unsupported_format(self, string_property_factory): from openapi_python_client.parser.properties import property_from_data name = "unknown" required = True nullable = True data = oai.Schema.construct(type="string", schema_format="blah", nullable=nullable) p, _ = property_from_data( name=name, required=required, data=data, schemas=Schemas, config=Config(), parent_name=None ) assert p == string_property_factory(name=name, required=required, nullable=nullable)
def test_generate_url(self, _create_new_client): url = "cool.url" from openapi_python_client.cli import Config, MetaType, app result = runner.invoke(app, ["generate", f"--url={url}"]) assert result.exit_code == 0 _create_new_client.assert_called_once_with(url=url, path=None, custom_template_path=None, meta=MetaType.POETRY, file_encoding="utf-8", config=Config())
def make_project(**kwargs): from unittest.mock import MagicMock from openapi_python_client import MetaType, Project kwargs = { "openapi": MagicMock(title="My Test API"), "meta": MetaType.POETRY, "config": Config(), **kwargs } return Project(**kwargs)
def test_no_format(self, string_property_factory, nullable, required): from openapi_python_client.parser.properties import property_from_data name = "some_prop" data = oai.Schema.construct(type="string", nullable=nullable, default='"hello world"', pattern="abcdef") p, _ = property_from_data( name=name, required=required, data=data, parent_name=None, config=Config(), schemas=Schemas() ) assert p == string_property_factory( name=name, required=required, nullable=nullable, default="'\\\\\"hello world\\\\\"'", pattern=data.pattern )
def test_invalid_reference(self, model_property_factory): from openapi_python_client.parser.properties import Schemas from openapi_python_client.parser.properties.model_property import _process_properties data = oai.Schema.construct( allOf=[oai.Reference.construct(ref="ThisIsNotGood")]) schemas = Schemas() result = _process_properties(data=data, schemas=schemas, class_name="", config=Config()) assert isinstance(result, PropertyError)
def test_model_bad_properties(self): from openapi_python_client.parser.properties import Schemas, build_model_property data = oai.Schema(properties={ "bad": oai.Reference.construct(ref="#/components/schema/NotExist"), }, ) result = build_model_property(data=data, name="prop", schemas=Schemas(), required=True, parent_name="parent", config=Config())[0] assert isinstance(result, PropertyError)
def test_update_path(self, _update_existing_client): path = "cool/path" from openapi_python_client.cli import Config, MetaType, app result = runner.invoke(app, ["update", f"--path={path}"]) assert result.exit_code == 0 _update_existing_client.assert_called_once_with( url=None, path=Path(path), custom_template_path=None, meta=MetaType.POETRY, file_encoding="utf-8", config=Config(), )
def test_process_properties_reference_not_exist(self): from openapi_python_client.parser.properties import Schemas from openapi_python_client.parser.properties.model_property import _process_properties data = oai.Schema(properties={ "bad": oai.Reference.construct(ref="#/components/schema/NotExist"), }, ) result = _process_properties(data=data, class_name="", schemas=Schemas(), config=Config()) assert isinstance(result, PropertyError)
def test_additional_schemas(self, additional_properties_schema, expected_additional_properties): from openapi_python_client.parser.properties import Schemas, build_model_property data = oai.Schema.construct( additionalProperties=additional_properties_schema, ) model, _ = build_model_property(data=data, name="prop", schemas=Schemas(), required=True, parent_name="parent", config=Config()) assert model.additional_properties == expected_additional_properties
def test_project_and_package_names(self, mocker, project_override, package_override, expected_project_name, expected_package_name): openapi = mocker.MagicMock(title="My Test API") from openapi_python_client import MetaType, Project project = Project( openapi=openapi, meta=MetaType.POETRY, config=Config(project_name_override=project_override, package_name_override=package_override), ) assert project.project_name == expected_project_name assert project.package_name == expected_package_name
def test_generate_meta(self, _create_new_client): path = "cool/path" from openapi_python_client.cli import Config, MetaType, app result = runner.invoke(app, ["generate", f"--path={path}", "--meta=none"]) assert result.exit_code == 0 _create_new_client.assert_called_once_with( url=None, path=Path(path), custom_template_path=None, meta=MetaType.NONE, file_encoding="utf-8", config=Config(), )
def test_non_model_reference(self, enum_property_factory): from openapi_python_client.parser.properties import Schemas from openapi_python_client.parser.properties.model_property import _process_properties data = oai.Schema.construct( allOf=[oai.Reference.construct(ref="#/First")]) schemas = Schemas(classes_by_reference={ "/First": enum_property_factory(), }) result = _process_properties(data=data, schemas=schemas, class_name="", config=Config()) assert isinstance(result, PropertyError)
def test_date_format(self, date_property_factory): from openapi_python_client.parser.properties import property_from_data name = "date_prop" required = True nullable = True data = oai.Schema.construct(type="string", schema_format="date", nullable=nullable, default="2020-11-06") p, _ = property_from_data( name=name, required=required, data=data, schemas=Schemas(), config=Config(), parent_name=None ) assert p == date_property_factory( name=name, required=required, nullable=nullable, default=f"isoparse('{data.default}').date()" )