From 03eeddbabf9259dd083a4055809ba62d26178e6c Mon Sep 17 00:00:00 2001 From: KotlinIsland <65446343+KotlinIsland@users.noreply.github.com> Date: Mon, 17 Apr 2023 03:16:27 +1000 Subject: [PATCH] =?UTF-8?q?(=F0=9F=8E=81)=20infer=20data=20vs=20schema=20w?= =?UTF-8?q?hen=20`--input-file-type`=20is=20auto=20(#1249)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * infer data vs schema when `--input-file-type` is auto * Improve is_schema conditions * Fix coverage * Fix is_schema * Improve coverage * Improve coverage * Improve coverage --------- Co-authored-by: KotlinIsland Co-authored-by: Koudai Aono --- datamodel_code_generator/__init__.py | 46 +++++++++++++++++-- tests/data/jsonschema/items_boolean.json | 2 +- tests/data/jsonschema/root_id.json | 2 +- .../data/jsonschema/root_id_absolute_url.json | 2 +- tests/data/jsonschema/root_id_ref.json | 2 +- tests/data/jsonschema/root_id_self_ref.json | 2 +- tests/data/openapi/complex_reference.json | 1 + tests/data/openapi/datetime.yaml | 1 + tests/data/openapi/definitions.yaml | 1 + tests/data/openapi/discriminator.yaml | 1 + .../openapi/override_required_all_of.yaml | 1 + tests/data/openapi/x_enum_varnames.yaml | 2 +- tests/root_id.json | 2 +- tests/test_infer_input_type.py | 46 +++++++++++++++++++ 14 files changed, 99 insertions(+), 12 deletions(-) create mode 100644 tests/test_infer_input_type.py diff --git a/datamodel_code_generator/__init__.py b/datamodel_code_generator/__init__.py index 1b7bcab66..b5ccb464f 100644 --- a/datamodel_code_generator/__init__.py +++ b/datamodel_code_generator/__init__.py @@ -168,6 +168,37 @@ def is_openapi(text: str) -> bool: return 'openapi' in load_yaml(text) +JSON_SCHEMA_URLS: Tuple[str, ...] = ( + 'http://json-schema.org/', + 'https://json-schema.org/', +) + + +def is_schema(text: str) -> bool: + data = load_yaml(text) + if not isinstance(data, dict): + return False + schema = data.get('$schema') + if isinstance(schema, str) and any( + schema.startswith(u) for u in JSON_SCHEMA_URLS + ): # pragma: no cover + return True + if isinstance(data.get('type'), str): + return True + if any( + isinstance(data.get(o), list) + for o in ( + 'allOf', + 'anyOf', + 'oneOf', + ) + ): + return True + if isinstance(data.get('properties'), dict): + return True + return False + + class InputFileType(Enum): Auto = 'auto' OpenAPI = 'openapi' @@ -304,11 +335,8 @@ def generate( if isinstance(input_, Path) else input_text ) - input_file_type = ( - InputFileType.OpenAPI - if is_openapi(input_text_) # type: ignore - else InputFileType.JsonSchema - ) + assert isinstance(input_text_, str) + input_file_type = infer_input_type(input_text_) print( inferred_message.format(input_file_type.value), file=sys.stderr, @@ -483,6 +511,14 @@ def get_header_and_first_line(csv_file: IO[str]) -> Dict[str, Any]: file.close() +def infer_input_type(text: str) -> InputFileType: + if is_openapi(text): + return InputFileType.OpenAPI + elif is_schema(text): + return InputFileType.JsonSchema + return InputFileType.Json + + inferred_message = ( 'The input file type was determined to be: {}\nThis can be specificied explicitly with the ' '`--input-file-type` option.' diff --git a/tests/data/jsonschema/items_boolean.json b/tests/data/jsonschema/items_boolean.json index e12ab0fcc..8038870f3 100644 --- a/tests/data/jsonschema/items_boolean.json +++ b/tests/data/jsonschema/items_boolean.json @@ -1,5 +1,5 @@ { - "$schema ": "http://json-schema.org/draft-07/schema#", + "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "properties": { "example": { diff --git a/tests/data/jsonschema/root_id.json b/tests/data/jsonschema/root_id.json index 5dee01e1c..b62bcde32 100644 --- a/tests/data/jsonschema/root_id.json +++ b/tests/data/jsonschema/root_id.json @@ -1,6 +1,6 @@ { "$id": "https://example.com/root_id.json", - "$schema ": "http://json-schema.org/draft-07/schema#", + "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { "Person": { "$ref": "person.json" diff --git a/tests/data/jsonschema/root_id_absolute_url.json b/tests/data/jsonschema/root_id_absolute_url.json index 9ea3e152e..4ac23adc6 100644 --- a/tests/data/jsonschema/root_id_absolute_url.json +++ b/tests/data/jsonschema/root_id_absolute_url.json @@ -1,6 +1,6 @@ { "$id": "https://example.com/root_id.json", - "$schema ": "http://json-schema.org/draft-07/schema#", + "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { "Person": { "$ref": "person.json" diff --git a/tests/data/jsonschema/root_id_ref.json b/tests/data/jsonschema/root_id_ref.json index 4e73314c7..f7de99854 100644 --- a/tests/data/jsonschema/root_id_ref.json +++ b/tests/data/jsonschema/root_id_ref.json @@ -1,5 +1,5 @@ { - "$schema ": "http://json-schema.org/draft-07/schema#", + "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { "Person": { "$ref": "root_id.json#/definitions/Person" diff --git a/tests/data/jsonschema/root_id_self_ref.json b/tests/data/jsonschema/root_id_self_ref.json index 45dcfe644..5c8acb509 100644 --- a/tests/data/jsonschema/root_id_self_ref.json +++ b/tests/data/jsonschema/root_id_self_ref.json @@ -1,6 +1,6 @@ { "$id": "https://example.com/root_id_self_ref.json", - "$schema ": "http://json-schema.org/draft-07/schema#", + "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { "Person": { "$ref": "person.json" diff --git a/tests/data/openapi/complex_reference.json b/tests/data/openapi/complex_reference.json index 24fee52cc..1d89f9d2a 100644 --- a/tests/data/openapi/complex_reference.json +++ b/tests/data/openapi/complex_reference.json @@ -1,4 +1,5 @@ { + "openapi": "3.0.0", "components": { "schemas": { "A": { diff --git a/tests/data/openapi/datetime.yaml b/tests/data/openapi/datetime.yaml index 21288b3fb..9c0a73b11 100644 --- a/tests/data/openapi/datetime.yaml +++ b/tests/data/openapi/datetime.yaml @@ -1,3 +1,4 @@ +openapi: "3.0.0" components: schemas: InventoryItem: diff --git a/tests/data/openapi/definitions.yaml b/tests/data/openapi/definitions.yaml index 7e6b7d3db..2e99635d7 100644 --- a/tests/data/openapi/definitions.yaml +++ b/tests/data/openapi/definitions.yaml @@ -1,3 +1,4 @@ +openapi: "3.0.0" schemas: Problem: properties: diff --git a/tests/data/openapi/discriminator.yaml b/tests/data/openapi/discriminator.yaml index 334c50f93..9a611ae1b 100644 --- a/tests/data/openapi/discriminator.yaml +++ b/tests/data/openapi/discriminator.yaml @@ -1,3 +1,4 @@ +openapi: "3.0.0" components: schemas: ObjectBase: diff --git a/tests/data/openapi/override_required_all_of.yaml b/tests/data/openapi/override_required_all_of.yaml index 957261522..9c5eeee89 100644 --- a/tests/data/openapi/override_required_all_of.yaml +++ b/tests/data/openapi/override_required_all_of.yaml @@ -1,3 +1,4 @@ +openapi: "3.0.0" components: schemas: ObjectBase: diff --git a/tests/data/openapi/x_enum_varnames.yaml b/tests/data/openapi/x_enum_varnames.yaml index 5a9866554..1b778769e 100644 --- a/tests/data/openapi/x_enum_varnames.yaml +++ b/tests/data/openapi/x_enum_varnames.yaml @@ -1,4 +1,4 @@ -openapi: 3.0 +openapi: "3.0.0" components: schemas: string: diff --git a/tests/root_id.json b/tests/root_id.json index 9ea3e152e..4ac23adc6 100644 --- a/tests/root_id.json +++ b/tests/root_id.json @@ -1,6 +1,6 @@ { "$id": "https://example.com/root_id.json", - "$schema ": "http://json-schema.org/draft-07/schema#", + "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { "Person": { "$ref": "person.json" diff --git a/tests/test_infer_input_type.py b/tests/test_infer_input_type.py new file mode 100644 index 000000000..27b74afd9 --- /dev/null +++ b/tests/test_infer_input_type.py @@ -0,0 +1,46 @@ +from pathlib import Path + +from datamodel_code_generator import InputFileType, infer_input_type + +DATA_PATH: Path = Path(__file__).parent / 'data' + + +def test_infer_input_type(): + def assert_infer_input_type(file: Path, raw_data_type: InputFileType) -> None: + __tracebackhide__ = True + if file.is_dir(): + return + if file.suffix not in ('.yaml', '.json'): + return + result = infer_input_type(file.read_text()) + assert result == raw_data_type, f'{file} was the wrong type!' + + for file in (DATA_PATH / 'json').rglob('*'): + if str(file).endswith('broken.json'): + continue + assert_infer_input_type(file, InputFileType.Json) + for file in (DATA_PATH / 'jsonschema').rglob('*'): + if str(file).endswith(('external_child.json', 'external_child.yaml')): + continue + if 'reference_same_hierarchy_directory' in str(file): + continue + assert_infer_input_type(file, InputFileType.JsonSchema) + for file in (DATA_PATH / 'openapi').rglob('*'): + if str(file).endswith( + ( + 'aliases.json', + 'extra_data.json', + 'invalid.yaml', + 'list.json', + 'empty_data.json', + 'root_model.yaml', + 'json_pointer.yaml', + 'const.json', + ) + ): + continue + + if str(file).endswith('not.json'): + assert_infer_input_type(file, InputFileType.Json) + continue + assert_infer_input_type(file, InputFileType.OpenAPI)