Skip to content

Commit

Permalink
(🎁) infer data vs schema when --input-file-type is auto (#1249)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Co-authored-by: Koudai Aono <[email protected]>
  • Loading branch information
3 people authored Apr 16, 2023
1 parent 083691c commit 03eeddb
Show file tree
Hide file tree
Showing 14 changed files with 99 additions and 12 deletions.
46 changes: 41 additions & 5 deletions datamodel_code_generator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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.'
Expand Down
2 changes: 1 addition & 1 deletion tests/data/jsonschema/items_boolean.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema ": "http://json-schema.org/draft-07/schema#",
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"example": {
Expand Down
2 changes: 1 addition & 1 deletion tests/data/jsonschema/root_id.json
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
2 changes: 1 addition & 1 deletion tests/data/jsonschema/root_id_absolute_url.json
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
2 changes: 1 addition & 1 deletion tests/data/jsonschema/root_id_ref.json
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
2 changes: 1 addition & 1 deletion tests/data/jsonschema/root_id_self_ref.json
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
1 change: 1 addition & 0 deletions tests/data/openapi/complex_reference.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"openapi": "3.0.0",
"components": {
"schemas": {
"A": {
Expand Down
1 change: 1 addition & 0 deletions tests/data/openapi/datetime.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
openapi: "3.0.0"
components:
schemas:
InventoryItem:
Expand Down
1 change: 1 addition & 0 deletions tests/data/openapi/definitions.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
openapi: "3.0.0"
schemas:
Problem:
properties:
Expand Down
1 change: 1 addition & 0 deletions tests/data/openapi/discriminator.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
openapi: "3.0.0"
components:
schemas:
ObjectBase:
Expand Down
1 change: 1 addition & 0 deletions tests/data/openapi/override_required_all_of.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
openapi: "3.0.0"
components:
schemas:
ObjectBase:
Expand Down
2 changes: 1 addition & 1 deletion tests/data/openapi/x_enum_varnames.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
openapi: 3.0
openapi: "3.0.0"
components:
schemas:
string:
Expand Down
2 changes: 1 addition & 1 deletion tests/root_id.json
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
46 changes: 46 additions & 0 deletions tests/test_infer_input_type.py
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit 03eeddb

Please sign in to comment.