Skip to content

Commit edbcdc1

Browse files
committed
Add @Final markers to type system classes for mypyc safety
- Mark type classes @Final (use composition, not inheritance) - Add ClassVar to reserved_types for mypyc compatibility - Refactor GraphQLResolveInfo to use TYPE_CHECKING pattern Classes: GraphQLScalarType, GraphQLObjectType, GraphQLInterfaceType, GraphQLUnionType, GraphQLEnumType, GraphQLInputObjectType, GraphQLField, GraphQLArgument, GraphQLInputField, GraphQLEnumValue, GraphQLList, GraphQLNonNull, GraphQLDirective, GraphQLSchema
1 parent 7eaf273 commit edbcdc1

3 files changed

Lines changed: 27 additions & 9 deletions

File tree

src/graphql/type/definition.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
from typing import (
88
TYPE_CHECKING,
99
Any,
10+
ClassVar,
1011
Generic,
1112
NamedTuple,
1213
TypedDict,
1314
TypeVar,
1415
cast,
16+
final,
1517
overload,
1618
)
1719

@@ -230,7 +232,7 @@ class GraphQLNamedType(GraphQLType):
230232
ast_node: TypeDefinitionNode | None
231233
extension_ast_nodes: tuple[TypeExtensionNode, ...]
232234

233-
reserved_types: Mapping[str, GraphQLNamedType] = {}
235+
reserved_types: ClassVar[Mapping[str, GraphQLNamedType]] = {}
234236

235237
def __new__(cls, name: str, *_args: Any, **_kwargs: Any) -> GraphQLNamedType:
236238
"""Create a GraphQL named type."""
@@ -318,6 +320,7 @@ class GraphQLScalarTypeKwargs(GraphQLNamedTypeKwargs, total=False):
318320
specified_by_url: str | None
319321

320322

323+
@final
321324
class GraphQLScalarType(GraphQLNamedType):
322325
"""Scalar Type Definition
323326
@@ -467,6 +470,7 @@ class GraphQLFieldKwargs(TypedDict, total=False):
467470
ast_node: FieldDefinitionNode | None
468471

469472

473+
@final
470474
class GraphQLField: # noqa: PLW1641
471475
"""Definition of a GraphQL field"""
472476

@@ -544,9 +548,12 @@ def __copy__(self) -> GraphQLField: # pragma: no cover
544548

545549
TContext = TypeVar("TContext") # pylint: disable=invalid-name
546550

547-
try:
551+
# Use TYPE_CHECKING for generic version (type checkers), simple version at runtime.
552+
# This avoids mypyc issues with conditional class definitions and Python 3.10
553+
# incompatibility with NamedTuple + Generic.
554+
if TYPE_CHECKING:
548555

549-
class GraphQLResolveInfo(NamedTuple, Generic[TContext]): # pyright: ignore
556+
class GraphQLResolveInfo(NamedTuple, Generic[TContext]):
550557
"""Collection of information passed to the resolvers.
551558
552559
This is always passed as the first argument to the resolvers.
@@ -568,11 +575,10 @@ class GraphQLResolveInfo(NamedTuple, Generic[TContext]): # pyright: ignore
568575
variable_values: dict[str, Any]
569576
context: TContext
570577
is_awaitable: Callable[[Any], TypeGuard[Awaitable]]
571-
except TypeError as error: # pragma: no cover
572-
if "Multiple inheritance with NamedTuple is not supported" not in str(error):
573-
raise # only catch expected error for Python 3.10
574578

575-
class GraphQLResolveInfo(NamedTuple): # type: ignore[no-redef]
579+
else:
580+
581+
class GraphQLResolveInfo(NamedTuple):
576582
"""Collection of information passed to the resolvers.
577583
578584
This is always passed as the first argument to the resolvers.
@@ -632,6 +638,7 @@ class GraphQLArgumentKwargs(TypedDict, total=False):
632638
ast_node: InputValueDefinitionNode | None
633639

634640

641+
@final
635642
class GraphQLArgument: # noqa: PLW1641
636643
"""Definition of a GraphQL argument"""
637644

@@ -701,6 +708,7 @@ class GraphQLObjectTypeKwargs(GraphQLNamedTypeKwargs, total=False):
701708
is_type_of: GraphQLIsTypeOfFn | None
702709

703710

711+
@final
704712
class GraphQLObjectType(GraphQLNamedType):
705713
"""Object Type Definition
706714
@@ -818,6 +826,7 @@ class GraphQLInterfaceTypeKwargs(GraphQLNamedTypeKwargs, total=False):
818826
resolve_type: GraphQLTypeResolver | None
819827

820828

829+
@final
821830
class GraphQLInterfaceType(GraphQLNamedType):
822831
"""Interface Type Definition
823832
@@ -921,6 +930,7 @@ class GraphQLUnionTypeKwargs(GraphQLNamedTypeKwargs, total=False):
921930
resolve_type: GraphQLTypeResolver | None
922931

923932

933+
@final
924934
class GraphQLUnionType(GraphQLNamedType):
925935
"""Union Type Definition
926936
@@ -1013,6 +1023,7 @@ class GraphQLEnumTypeKwargs(GraphQLNamedTypeKwargs, total=False):
10131023
names_as_values: bool | None
10141024

10151025

1026+
@final
10161027
class GraphQLEnumType(GraphQLNamedType):
10171028
"""Enum Type Definition
10181029
@@ -1209,6 +1220,7 @@ class GraphQLEnumValueKwargs(TypedDict, total=False):
12091220
ast_node: EnumValueDefinitionNode | None
12101221

12111222

1223+
@final
12121224
class GraphQLEnumValue: # noqa: PLW1641
12131225
"""A GraphQL enum value."""
12141226

@@ -1267,6 +1279,7 @@ class GraphQLInputObjectTypeKwargs(GraphQLNamedTypeKwargs, total=False):
12671279
is_one_of: bool
12681280

12691281

1282+
@final
12701283
class GraphQLInputObjectType(GraphQLNamedType):
12711284
"""Input Object Type Definition
12721285
@@ -1383,6 +1396,7 @@ class GraphQLInputFieldKwargs(TypedDict, total=False):
13831396
ast_node: InputValueDefinitionNode | None
13841397

13851398

1399+
@final
13861400
class GraphQLInputField: # noqa: PLW1641
13871401
"""Definition of a GraphQL input field"""
13881402

@@ -1447,6 +1461,7 @@ def is_required_input_field(field: GraphQLInputField) -> bool:
14471461
# Wrapper types
14481462

14491463

1464+
@final
14501465
class GraphQLList(GraphQLWrappingType[GT_co]):
14511466
"""List Type Wrapper
14521467
@@ -1489,6 +1504,7 @@ def assert_list_type(type_: Any) -> GraphQLList:
14891504
GNT_co = TypeVar("GNT_co", bound="GraphQLNullableType", covariant=True)
14901505

14911506

1507+
@final
14921508
class GraphQLNonNull(GraphQLWrappingType[GNT_co]):
14931509
"""Non-Null Type Wrapper
14941510

src/graphql/type/directives.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from __future__ import annotations
44

5-
from typing import TYPE_CHECKING, Any, TypedDict, TypeGuard, cast
5+
from typing import TYPE_CHECKING, Any, TypedDict, TypeGuard, cast, final
66

77
from ..language import DirectiveLocation, ast
88
from ..pyutils import inspect
@@ -44,6 +44,7 @@ class GraphQLDirectiveKwargs(TypedDict, total=False):
4444
ast_node: ast.DirectiveDefinitionNode | None
4545

4646

47+
@final
4748
class GraphQLDirective: # noqa: PLW1641
4849
"""GraphQL Directive
4950

src/graphql/type/schema.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from ..error import GraphQLError
1717
from ..language import OperationType, ast
1818

19-
from typing import TypeAlias, TypedDict, TypeGuard
19+
from typing import TypeAlias, TypedDict, TypeGuard, final
2020

2121
from ..pyutils import inspect
2222
from .definition import (
@@ -68,6 +68,7 @@ class GraphQLSchemaKwargs(TypedDict, total=False):
6868
assume_valid: bool
6969

7070

71+
@final
7172
class GraphQLSchema:
7273
"""Schema Definition
7374

0 commit comments

Comments
 (0)