Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🚑 fixes graphql parser --use-standard-collections --use-union-operator --use-annotated #2016

Merged
merged 25 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ee63229
:adhesive_bandage: fixes graphql parser use-standard-collections and …
bpsoos Jun 27, 2024
98fff67
:adhesive_bandage: fixes graphql parser to use annoteted on typename …
bpsoos Jun 27, 2024
1981491
Merge branch 'koxudaxi:main' into fix/1941-graphql-options
bpsoos Jun 27, 2024
8326eb8
:recycle: refactors tests
bpsoos Jun 28, 2024
63b5c81
:recycle: refactors tests
bpsoos Jun 28, 2024
5c88ec8
:recycle: refactors tests
bpsoos Jun 28, 2024
10c791e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 28, 2024
ca68259
:adhesive_bandage: fixes failing test
bpsoos Jun 28, 2024
81d1388
:recycle: refactors test_main into multiple files
bpsoos Jun 28, 2024
3079220
:recycle: refactors test_main into multiple files
bpsoos Jun 28, 2024
3650361
:adhesive_bandage: fixes msgspec output file name
bpsoos Jun 28, 2024
52521d1
:recycle: refactors jsonschema expectations
bpsoos Jun 28, 2024
1c64f25
:recycle: refactors jsonschema expectations
bpsoos Jun 28, 2024
4fff872
:recycle: refactors jsonschema expectations
bpsoos Jun 28, 2024
e675f3e
:recycle: refactors openapi expectations
bpsoos Jun 28, 2024
cd0006b
:recycle: refactors csv json yaml and general expectations
bpsoos Jun 28, 2024
fe9f1fc
Merge branch 'main' into fix/1941-graphql-options
bpsoos Jun 28, 2024
4399639
Fix test coverage (#2020)
koxudaxi Jul 1, 2024
ae92e73
Fix coverage (#2023)
koxudaxi Jul 1, 2024
d381a91
docs: Update airbyte use case + fix broken link (#2021)
natikgadzhi Jul 1, 2024
c7b391b
formats
bpsoos Jul 1, 2024
89d9359
Merge remote-tracking branch 'origin/main' into fix/1941-graphql-options
bpsoos Jul 1, 2024
d695643
Merge remote-tracking branch 'origin' into fix/1941-graphql-options
bpsoos Jul 1, 2024
e05fa78
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 1, 2024
7a33cd8
Merge branch 'main' into fix/1941-graphql-options
bpsoos Jul 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions datamodel_code_generator/parser/graphql.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,7 @@
escape_characters,
)
from datamodel_code_generator.reference import ModelType, Reference
from datamodel_code_generator.types import (
DataTypeManager,
StrictTypes,
Types,
)
from datamodel_code_generator.types import DataTypeManager, StrictTypes, Types

try:
import graphql
Expand Down Expand Up @@ -233,6 +229,8 @@ def __init__(

self.data_model_scalar_type = data_model_scalar_type
self.data_model_union_type = data_model_union_type
self.use_standard_collections = use_standard_collections
self.use_union_operator = use_union_operator

def _get_context_source_path_parts(self) -> Iterator[Tuple[Source, List[str]]]:
# TODO (denisart): Temporarily this method duplicates
Expand Down Expand Up @@ -283,8 +281,13 @@ def _resolve_types(self, paths: List[str], schema: graphql.GraphQLSchema) -> Non
def _typename_field(self, name: str) -> DataModelFieldBase:
return self.data_model_field_type(
name='typename__',
data_type=DataType(literals=[name]),
data_type=DataType(
literals=[name],
use_union_operator=self.use_union_operator,
use_standard_collections=self.use_standard_collections,
),
default=name,
use_annotated=self.use_annotated,
required=False,
alias='__typename',
use_one_literal_as_default=True,
Expand Down Expand Up @@ -348,15 +351,23 @@ def parse_field(
alias: str,
field: Union[graphql.GraphQLField, graphql.GraphQLInputField],
) -> DataModelFieldBase:
final_data_type = DataType(is_optional=True)
final_data_type = DataType(
is_optional=True,
use_union_operator=self.use_union_operator,
use_standard_collections=self.use_standard_collections,
)
data_type = final_data_type
obj = field.type

while graphql.is_list_type(obj) or graphql.is_non_null_type(obj):
if graphql.is_list_type(obj):
data_type.is_list = True

new_data_type = DataType(is_optional=True)
new_data_type = DataType(
is_optional=True,
use_union_operator=self.use_union_operator,
use_standard_collections=self.use_standard_collections,
)
data_type.data_types = [new_data_type]

data_type = new_data_type
Expand Down
7 changes: 1 addition & 6 deletions datamodel_code_generator/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,7 @@

import pydantic
from packaging import version
from pydantic import (
StrictBool,
StrictInt,
StrictStr,
create_model,
)
from pydantic import StrictBool, StrictInt, StrictStr, create_model

from datamodel_code_generator.format import PythonVersion
from datamodel_code_generator.imports import (
Expand Down
28 changes: 28 additions & 0 deletions tests/data/expected/main/main_graphql_annotated/output.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# generated by datamodel-codegen:
# filename: annotated.graphql
# timestamp: 2019-07-26T00:00:00+00:00

from __future__ import annotations

from typing import List, Optional, TypeAlias

from pydantic import BaseModel, Field
from typing_extensions import Annotated, Literal

Boolean: TypeAlias = bool
"""
The `Boolean` scalar type represents `true` or `false`.
"""


String: TypeAlias = str
"""
The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.
"""


class A(BaseModel):
field: String
listField: List[String]
listListField: List[List[String]]
typename__: Annotated[Optional[Literal['A']], Field(alias='__typename')] = 'A'
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# generated by datamodel-codegen:
# filename: use-standard-collections.graphql
# timestamp: 2019-07-26T00:00:00+00:00

from __future__ import annotations

from typing import Optional, TypeAlias

from pydantic import BaseModel, Field
from typing_extensions import Literal

Boolean: TypeAlias = bool
"""
The `Boolean` scalar type represents `true` or `false`.
"""


String: TypeAlias = str
"""
The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.
"""


class A(BaseModel):
field: String
listField: list[String]
listListField: list[list[String]]
typename__: Optional[Literal['A']] = Field('A', alias='__typename')
44 changes: 44 additions & 0 deletions tests/data/expected/main/main_graphql_use_union_operator/output.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# generated by datamodel-codegen:
# filename: use-union-operator.graphql
# timestamp: 2019-07-26T00:00:00+00:00

from __future__ import annotations

from typing import List, TypeAlias

from pydantic import BaseModel, Field
from typing_extensions import Literal

Boolean: TypeAlias = bool
"""
The `Boolean` scalar type represents `true` or `false`.
"""


String: TypeAlias = str
"""
The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.
"""


class A(BaseModel):
field: String
listField: List[String]
listListField: List[List[String]]
listListOptionalField: List[List[String | None]]
listOptionalField: List[String | None]
listOptionalListField: List[List[String] | None]
listOptionalListOptionalField: List[List[String | None] | None]
optionalField: String | None = None
optionalListListField: List[List[String]] | None = Field(default_factory=list)
optionalListListOptionalField: List[List[String | None]] | None = Field(
default_factory=list
)
optionalListOptionalField: List[String | None] | None = Field(default_factory=list)
optionalListOptionalListField: List[List[String] | None] | None = Field(
default_factory=list
)
optionalListOptionalListOptionalField: List[
List[String | None] | None
] | None = Field(default_factory=list)
typename__: Literal['A'] | None = Field('A', alias='__typename')
2 changes: 1 addition & 1 deletion tests/data/graphql/additional-imports.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ type A {
a: Date!
b: DateTime!
c: MyCustomClass!
}
}
5 changes: 5 additions & 0 deletions tests/data/graphql/annotated.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type A {
field: String!
listField: [String!]!
listListField:[[String!]!]!
}
6 changes: 6 additions & 0 deletions tests/data/graphql/use-standard-collections.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type A {
field: String!
listField: [String!]!
listListField:[[String!]!]!
}

15 changes: 15 additions & 0 deletions tests/data/graphql/use-union-operator.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
type A {
field: String!
optionalField: String
optionalListOptionalField: [String]
listOptionalField: [String]!
listField: [String!]!
optionalListOptionalListOptionalField:[[String]]
optionalListListOptionalField:[[String]!]
listListOptionalField:[[String]!]!
listOptionalListOptionalField:[[String]]!
optionalListOptionalListField:[[String!]]
optionalListListField:[[String!]!]
listListField:[[String!]!]!
listOptionalListField:[[String!]]!
}
84 changes: 84 additions & 0 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6804,6 +6804,90 @@ def test_main_graphql_custom_formatters():
)


@freeze_time('2019-07-26')
@pytest.mark.skipif(
black.__version__.split('.')[0] == '19',
reason="Installed black doesn't support the old style",
)
def test_main_graphql_use_standard_collections():
with TemporaryDirectory() as output_dir:
output_file: Path = Path(output_dir) / 'output.py'
return_code: Exit = main(
[
'--input',
str(GRAPHQL_DATA_PATH / 'use-standard-collections.graphql'),
'--output',
str(output_file),
'--input-file-type',
'graphql',
'--use-standard-collections',
]
)
assert return_code == Exit.OK
assert (
output_file.read_text()
== (
EXPECTED_MAIN_PATH
/ 'main_graphql_use_standard_collections'
/ 'output.py'
).read_text()
)


@freeze_time('2019-07-26')
@pytest.mark.skipif(
black.__version__.split('.')[0] == '19',
reason="Installed black doesn't support the old style",
)
def test_main_graphql_use_union_operator():
with TemporaryDirectory() as output_dir:
output_file: Path = Path(output_dir) / 'output.py'
return_code: Exit = main(
[
'--input',
str(GRAPHQL_DATA_PATH / 'use-union-operator.graphql'),
'--output',
str(output_file),
'--input-file-type',
'graphql',
'--use-union-operator',
]
)
assert return_code == Exit.OK
assert (
output_file.read_text()
== (
EXPECTED_MAIN_PATH / 'main_graphql_use_union_operator' / 'output.py'
).read_text()
)


@freeze_time('2019-07-26')
@pytest.mark.skipif(
black.__version__.split('.')[0] == '19',
reason="Installed black doesn't support the old style",
)
def test_main_graphql_annotated():
with TemporaryDirectory() as output_dir:
output_file: Path = Path(output_dir) / 'output.py'
return_code: Exit = main(
[
'--input',
str(GRAPHQL_DATA_PATH / 'annotated.graphql'),
'--output',
str(output_file),
'--input-file-type',
'graphql',
'--use-annotated',
]
)
assert return_code == Exit.OK
assert (
output_file.read_text()
== (EXPECTED_MAIN_PATH / 'main_graphql_annotated' / 'output.py').read_text()
)


@freeze_time('2019-07-26')
@pytest.mark.skipif(
black.__version__.split('.')[0] == '19',
Expand Down