Skip to content

Commit 2148938

Browse files
Fix GraphQL parser to handle renamed objects correctly (#2670)
* init * fix * Fix snapshots * use unique=False * Add conflict test * modify references logic * fix docstring * revert name change * Exclude else branch from coverage --------- Co-authored-by: Koudai Aono <koxudaxi@gmail.com>
1 parent 6aa5668 commit 2148938

12 files changed

Lines changed: 127 additions & 75 deletions

File tree

src/datamodel_code_generator/parser/graphql.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -484,12 +484,11 @@ def parse_field(
484484
obj = graphql.assert_wrapping_type(obj)
485485
obj = obj.of_type
486486

487-
if graphql.is_enum_type(obj):
488-
obj = graphql.assert_enum_type(obj)
489-
data_type.reference = self.references[obj.name]
490-
491487
obj = graphql.assert_named_type(obj)
492-
if data_type.reference is None:
488+
if obj.name in self.references:
489+
data_type.reference = self.references[obj.name]
490+
else: # pragma: no cover
491+
# Only happens for Query and Mutation root types
493492
data_type.type = obj.name
494493

495494
required = (not self.force_optional_for_required_fields) and (not final_data_type.is_optional)
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# generated by datamodel-codegen:
2+
# filename: casing.graphql
3+
# timestamp: 2019-07-26T00:00:00+00:00
4+
5+
from __future__ import annotations
6+
7+
from enum import Enum
8+
from typing import Literal, Optional
9+
10+
from pydantic import BaseModel, Field
11+
from typing_extensions import TypeAlias
12+
13+
Boolean: TypeAlias = bool
14+
"""
15+
The `Boolean` scalar type represents `true` or `false`.
16+
"""
17+
18+
19+
Int: TypeAlias = int
20+
"""
21+
The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
22+
"""
23+
24+
25+
String: TypeAlias = str
26+
"""
27+
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.
28+
"""
29+
30+
31+
class Lowercase(Enum):
32+
foo = 'foo'
33+
34+
35+
class Conflict(BaseModel):
36+
Bar: Int
37+
bar: String
38+
typename__: Optional[Literal['Conflict']] = Field('Conflict', alias='__typename')
39+
40+
41+
class ConflictModel(BaseModel):
42+
Foo: Int
43+
foo: String
44+
typename__: Optional[Literal['conflict']] = Field('conflict', alias='__typename')
45+
46+
47+
class Lowercasetype(BaseModel):
48+
foo: Int
49+
typename__: Optional[Literal['lowercasetype']] = Field(
50+
'lowercasetype', alias='__typename'
51+
)
52+
53+
54+
class Ref(BaseModel):
55+
bar: Lowercase
56+
baz: Lowercasetype
57+
eggs: Conflict
58+
spam: ConflictModel
59+
typename__: Optional[Literal['Ref']] = Field('Ref', alias='__typename')

tests/data/expected/main/graphql/enum_casing.py

Lines changed: 0 additions & 31 deletions
This file was deleted.

tests/data/expected/main/graphql/simple_star_wars.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,7 @@ class Vehicle(BaseModel):
153153
pilots_ids: List[ID]
154154
vehicle_class: Optional[String] = None
155155
typename__: Optional[Literal['Vehicle']] = Field('Vehicle', alias='__typename')
156+
157+
158+
Film.update_forward_refs()
159+
Person.update_forward_refs()

tests/data/expected/main/graphql/simple_star_wars_extra_fields_allow.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,7 @@ class Config:
171171
pilots_ids: List[ID]
172172
vehicle_class: Optional[String] = None
173173
typename__: Optional[Literal['Vehicle']] = Field('Vehicle', alias='__typename')
174+
175+
176+
Film.update_forward_refs()
177+
Person.update_forward_refs()

tests/data/expected/main/graphql/type_alias.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,6 @@
3030
"""
3131

3232

33-
class ModelWithTypeAliasField(BaseModel):
34-
simple_field: Optional[SimpleString] = None
35-
string_field: Optional[String] = None
36-
union_field: Optional[UnionType] = None
37-
typename__: Optional[Literal['ModelWithTypeAliasField']] = Field(
38-
'ModelWithTypeAliasField', alias='__typename'
39-
)
40-
41-
4233
class Person(BaseModel):
4334
age: Int
4435
name: String
@@ -55,3 +46,12 @@ class Pet(BaseModel):
5546
'Person',
5647
'Pet',
5748
]
49+
50+
51+
class ModelWithTypeAliasField(BaseModel):
52+
simple_field: Optional[SimpleString] = None
53+
string_field: Optional[String] = None
54+
union_field: Optional[UnionType] = None
55+
typename__: Optional[Literal['ModelWithTypeAliasField']] = Field(
56+
'ModelWithTypeAliasField', alias='__typename'
57+
)

tests/data/expected/main/graphql/type_alias_py312.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,6 @@
2929
"""
3030

3131

32-
class ModelWithTypeAliasField(BaseModel):
33-
simple_field: Optional[SimpleString] = None
34-
string_field: Optional[String] = None
35-
union_field: Optional[UnionType] = None
36-
typename__: Optional[Literal['ModelWithTypeAliasField']] = Field(
37-
'ModelWithTypeAliasField', alias='__typename'
38-
)
39-
40-
4132
class Person(BaseModel):
4233
age: Int
4334
name: String
@@ -54,3 +45,12 @@ class Pet(BaseModel):
5445
'Person',
5546
'Pet',
5647
]
48+
49+
50+
class ModelWithTypeAliasField(BaseModel):
51+
simple_field: Optional[SimpleString] = None
52+
string_field: Optional[String] = None
53+
union_field: Optional[UnionType] = None
54+
typename__: Optional[Literal['ModelWithTypeAliasField']] = Field(
55+
'ModelWithTypeAliasField', alias='__typename'
56+
)

tests/data/expected/parser/graphql/union-aliased-bug.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,6 @@ class GroupMetadata(BaseModel):
2828
)
2929

3030

31-
class Resource(BaseModel):
32-
metadata: UserMetadata
33-
typename__: Optional[Literal['Resource']] = Field('Resource', alias='__typename')
34-
35-
3631
class UserMetadata(BaseModel):
3732
name: String
3833
typename__: Optional[Literal['UserMetadata']] = Field(
@@ -44,3 +39,8 @@ class UserMetadata(BaseModel):
4439
'GroupMetadata',
4540
'UserMetadata',
4641
]
42+
43+
44+
class Resource(BaseModel):
45+
metadata: UserMetadata
46+
typename__: Optional[Literal['Resource']] = Field('Resource', alias='__typename')

tests/data/expected/parser/graphql/union-commented.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,6 @@ class GroupMetadata(BaseModel):
3232
)
3333

3434

35-
class Resource(BaseModel):
36-
metadata: UserMetadata
37-
typename__: Optional[Literal['Resource']] = Field('Resource', alias='__typename')
38-
39-
4035
class UserMetadata(BaseModel):
4136
"""
4237
This is a multiline comment,
@@ -64,3 +59,8 @@ class UserMetadata(BaseModel):
6459
'GroupMetadata',
6560
'UserMetadata',
6661
]
62+
63+
64+
class Resource(BaseModel):
65+
metadata: UserMetadata
66+
typename__: Optional[Literal['Resource']] = Field('Resource', alias='__typename')

tests/data/graphql/casing.graphql

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
enum lowercase {
2+
foo
3+
}
4+
5+
type lowercasetype {
6+
foo: Int!
7+
}
8+
9+
type conflict {
10+
foo: String!
11+
Foo: Int!
12+
}
13+
14+
type Conflict {
15+
bar: String!
16+
Bar: Int!
17+
}
18+
19+
type Ref {
20+
bar: lowercase!
21+
baz: lowercasetype!
22+
spam: conflict!
23+
eggs: Conflict!
24+
}

0 commit comments

Comments
 (0)