From 418e83af3a824db68f466c4e82daaba0cf78946f Mon Sep 17 00:00:00 2001 From: Leszek Hanusz Date: Fri, 5 Sep 2025 17:29:37 +0200 Subject: [PATCH 1/6] Install typing_extensions for Python versions < 3.11 Fix invalid sphinx-argparse version on Python 3.9 --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 3db1c9f8..39a6e453 100644 --- a/setup.py +++ b/setup.py @@ -7,6 +7,7 @@ "yarl>=1.6,<2.0", "backoff>=1.11.1,<3.0", "anyio>=3.0,<5", + "typing_extensions>=4.0.0; python_version<'3.11'", ] console_scripts = [ @@ -32,7 +33,8 @@ "sphinx>=7.0.0,<8;python_version<='3.9'", "sphinx>=8.1.0,<9;python_version>'3.9'", "sphinx_rtd_theme>=3.0.2,<4", - "sphinx-argparse==0.5.2", + "sphinx-argparse==0.5.2; python_version>='3.10'", + "sphinx-argparse==0.4.0; python_version<'3.10'", "types-aiofiles", "types-requests", ] + tests_requires From 257b60f64fc65f0c83baf7f065795b5f1db0480a Mon Sep 17 00:00:00 2001 From: Leszek Hanusz Date: Fri, 5 Sep 2025 17:30:02 +0200 Subject: [PATCH 2/6] Fix invalid typing on Python 3.9 --- gql/transport/aiohttp.py | 2 +- gql/transport/httpx.py | 2 +- gql/transport/requests.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gql/transport/aiohttp.py b/gql/transport/aiohttp.py index e3bfdb3b..ab26bd03 100644 --- a/gql/transport/aiohttp.py +++ b/gql/transport/aiohttp.py @@ -173,7 +173,7 @@ def _prepare_request( upload_files: bool = False, ) -> Dict[str, Any]: - payload: Dict | List + payload: Union[Dict, List] if isinstance(request, GraphQLRequest): payload = request.payload else: diff --git a/gql/transport/httpx.py b/gql/transport/httpx.py index 0a338639..7143f263 100644 --- a/gql/transport/httpx.py +++ b/gql/transport/httpx.py @@ -66,7 +66,7 @@ def _prepare_request( upload_files: bool = False, ) -> Dict[str, Any]: - payload: Dict | List + payload: Union[Dict, List] if isinstance(request, GraphQLRequest): payload = request.payload else: diff --git a/gql/transport/requests.py b/gql/transport/requests.py index a29f7f0f..8311c036 100644 --- a/gql/transport/requests.py +++ b/gql/transport/requests.py @@ -147,7 +147,7 @@ def _prepare_request( upload_files: bool = False, ) -> Dict[str, Any]: - payload: Dict | List + payload: Union[Dict, List] if isinstance(request, GraphQLRequest): payload = request.payload else: From 1473548e06794d6c66f39de7622e5ed54199b359 Mon Sep 17 00:00:00 2001 From: Leszek Hanusz Date: Fri, 5 Sep 2025 17:30:36 +0200 Subject: [PATCH 3/6] Modify gql/dsl.py to use the Self Python typing Remove the quotes around typing when possible --- gql/dsl.py | 72 +++++++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/gql/dsl.py b/gql/dsl.py index 2e6d3967..a1a1b69b 100644 --- a/gql/dsl.py +++ b/gql/dsl.py @@ -5,6 +5,7 @@ import logging import re +import sys from abc import ABC, abstractmethod from math import isfinite from typing import ( @@ -83,6 +84,11 @@ from .graphql_request import GraphQLRequest from .utils import to_camel_case +if sys.version_info >= (3, 11): + from typing import Self # pragma: no cover +else: + from typing_extensions import Self # pragma: no cover + log = logging.getLogger(__name__) _re_integer_string = re.compile("^-?(?:0|[1-9][0-9]*)$") @@ -457,7 +463,7 @@ class DSLDirective: behavior in a GraphQL document. """ - def __init__(self, name: str, dsl_schema: "DSLSchema"): + def __init__(self, name: str, dsl_schema: DSLSchema): r"""Initialize the DSLDirective with the given name and arguments. :param name: the name of the directive @@ -510,7 +516,7 @@ def name(self) -> str: """Get the directive name.""" return self.ast_directive.name.value - def __call__(self, **kwargs: Any) -> "DSLDirective": + def __call__(self, **kwargs: Any) -> Self: """Add arguments by calling the directive like a function. :param kwargs: directive arguments @@ -518,7 +524,7 @@ def __call__(self, **kwargs: Any) -> "DSLDirective": """ return self.args(**kwargs) - def args(self, **kwargs: Any) -> "DSLDirective": + def args(self, **kwargs: Any) -> Self: r"""Set the arguments of a directive The arguments are parsed to be stored in the AST of this field. @@ -584,7 +590,7 @@ def __init__(self, *args, **kwargs): self._directives = () @abstractmethod - def is_valid_directive(self, directive: "DSLDirective") -> bool: + def is_valid_directive(self, directive: DSLDirective) -> bool: """Check if a directive is valid for this DSL element. :param directive: The DSLDirective to validate @@ -594,7 +600,7 @@ def is_valid_directive(self, directive: "DSLDirective") -> bool: "Any DSLDirectable concrete class must have an is_valid_directive method" ) # pragma: no cover - def directives(self, *directives: DSLDirective) -> Any: + def directives(self, *directives: DSLDirective) -> Self: r"""Add directives to this DSL element. :param \*directives: DSLDirective instances to add @@ -799,7 +805,7 @@ def __repr__(self) -> str: class DSLQuery(DSLOperation): operation_type = OperationType.QUERY - def is_valid_directive(self, directive: "DSLDirective") -> bool: + def is_valid_directive(self, directive: DSLDirective) -> bool: """Check if directive is valid for Query operations.""" return DirectiveLocation.QUERY in directive.directive_def.locations @@ -807,7 +813,7 @@ def is_valid_directive(self, directive: "DSLDirective") -> bool: class DSLMutation(DSLOperation): operation_type = OperationType.MUTATION - def is_valid_directive(self, directive: "DSLDirective") -> bool: + def is_valid_directive(self, directive: DSLDirective) -> bool: """Check if directive is valid for Mutation operations.""" return DirectiveLocation.MUTATION in directive.directive_def.locations @@ -815,7 +821,7 @@ def is_valid_directive(self, directive: "DSLDirective") -> bool: class DSLSubscription(DSLOperation): operation_type = OperationType.SUBSCRIPTION - def is_valid_directive(self, directive: "DSLDirective") -> bool: + def is_valid_directive(self, directive: DSLDirective) -> bool: """Check if directive is valid for Subscription operations.""" return DirectiveLocation.SUBSCRIPTION in directive.directive_def.locations @@ -854,16 +860,16 @@ def to_ast_type(self, type_: GraphQLInputType) -> TypeNode: return NamedTypeNode(name=NameNode(value=type_.name)) - def set_type(self, type_: GraphQLInputType) -> "DSLVariable": + def set_type(self, type_: GraphQLInputType) -> Self: self.type = type_ self.ast_variable_type = self.to_ast_type(type_) return self - def default(self, default_value: Any) -> "DSLVariable": + def default(self, default_value: Any) -> Self: self.default_value = default_value return self - def is_valid_directive(self, directive: "DSLDirective") -> bool: + def is_valid_directive(self, directive: DSLDirective) -> bool: """Check if directive is valid for Variable definitions.""" for arg in directive.ast_directive.arguments: if isinstance(arg.value, VariableNode): @@ -894,7 +900,7 @@ def __init__(self): """:meta private:""" self.variables: Dict[str, DSLVariable] = {} - def __getattr__(self, name: str) -> "DSLVariable": + def __getattr__(self, name: str) -> DSLVariable: """Attributes of the DSLVariableDefinitions class are generated automatically with this dunder method in order to generate instances of :class:`DSLVariable` @@ -1097,7 +1103,7 @@ class DSLSelectableWithAlias(DSLSelectable): ast_field: FieldNode - def alias(self, alias: str) -> "DSLSelectableWithAlias": + def alias(self, alias: str) -> Self: """Set an alias .. note:: @@ -1168,10 +1174,10 @@ def name(self): """:meta private:""" return self.ast_field.name.value - def __call__(self, **kwargs: Any) -> "DSLField": + def __call__(self, **kwargs: Any) -> Self: return self.args(**kwargs) - def args(self, **kwargs: Any) -> "DSLField": + def args(self, **kwargs: Any) -> Self: r"""Set the arguments of a field The arguments are parsed to be stored in the AST of this field. @@ -1217,8 +1223,8 @@ def _get_argument(self, name: str) -> GraphQLArgument: return arg def select( - self, *fields: "DSLSelectable", **fields_with_alias: "DSLSelectableWithAlias" - ) -> "DSLField": + self, *fields: DSLSelectable, **fields_with_alias: DSLSelectableWithAlias + ) -> Self: """Calling :meth:`select ` method with corrected typing hints """ @@ -1228,14 +1234,14 @@ def select( return self - def directives(self, *directives: DSLDirective) -> "DSLField": + def directives(self, *directives: DSLDirective) -> Self: """Add directives to this field.""" super().directives(*directives) self.ast_field.directives = self.directives_ast return self - def is_valid_directive(self, directive: "DSLDirective") -> bool: + def is_valid_directive(self, directive: DSLDirective) -> bool: """Check if directive is valid for Field locations.""" return DirectiveLocation.FIELD in directive.directive_def.locations @@ -1277,7 +1283,7 @@ def __init__(self, name: str): super().__init__(name, self.meta_type, field) - def is_valid_directive(self, directive: "DSLDirective") -> bool: + def is_valid_directive(self, directive: DSLDirective) -> bool: """Check if directive is valid for MetaField locations (same as Field).""" return DirectiveLocation.FIELD in directive.directive_def.locations @@ -1290,8 +1296,8 @@ class DSLInlineFragment(DSLSelectable, DSLFragmentSelector): def __init__( self, - *fields: "DSLSelectable", - **fields_with_alias: "DSLSelectableWithAlias", + *fields: DSLSelectable, + **fields_with_alias: DSLSelectableWithAlias, ): r"""Initialize the DSLInlineFragment. @@ -1309,8 +1315,8 @@ def __init__( DSLDirectable.__init__(self) def select( - self, *fields: "DSLSelectable", **fields_with_alias: "DSLSelectableWithAlias" - ) -> "DSLInlineFragment": + self, *fields: DSLSelectable, **fields_with_alias: DSLSelectableWithAlias + ) -> Self: """Calling :meth:`select ` method with corrected typing hints """ @@ -1319,7 +1325,7 @@ def select( return self - def on(self, type_condition: DSLType) -> "DSLInlineFragment": + def on(self, type_condition: DSLType) -> Self: """Provides the GraphQL type of this inline fragment.""" self._type = type_condition._type @@ -1328,7 +1334,7 @@ def on(self, type_condition: DSLType) -> "DSLInlineFragment": ) return self - def directives(self, *directives: DSLDirective) -> "DSLInlineFragment": + def directives(self, *directives: DSLDirective) -> Self: """Add directives to this inline fragment. Inline fragments support all directive types through auto-validation. @@ -1347,7 +1353,7 @@ def __repr__(self) -> str: return f"<{self.__class__.__name__}{type_info}>" - def is_valid_directive(self, directive: "DSLDirective") -> bool: + def is_valid_directive(self, directive: DSLDirective) -> bool: """Check if directive is valid for Inline Fragment locations.""" return DirectiveLocation.INLINE_FRAGMENT in directive.directive_def.locations @@ -1381,7 +1387,7 @@ def name(self) -> str: """:meta private:""" return self.ast_field.name.value - def directives(self, *directives: DSLDirective) -> "DSLFragmentSpread": + def directives(self, *directives: DSLDirective) -> Self: """Add directives to this fragment spread. Fragment spreads support all directive types through auto-validation. @@ -1390,7 +1396,7 @@ def directives(self, *directives: DSLDirective) -> "DSLFragmentSpread": self.ast_field.directives = self.directives_ast return self - def is_valid_directive(self, directive: "DSLDirective") -> bool: + def is_valid_directive(self, directive: DSLDirective) -> bool: """Check if directive is valid for Fragment Spread locations.""" return DirectiveLocation.FRAGMENT_SPREAD in directive.directive_def.locations @@ -1444,8 +1450,8 @@ def spread(self) -> DSLFragmentSpread: return DSLFragmentSpread(self) def select( - self, *fields: "DSLSelectable", **fields_with_alias: "DSLSelectableWithAlias" - ) -> "DSLFragment": + self, *fields: DSLSelectable, **fields_with_alias: DSLSelectableWithAlias + ) -> Self: """Calling :meth:`select ` method with corrected typing hints """ @@ -1458,7 +1464,7 @@ def select( return self - def on(self, type_condition: DSLType) -> "DSLFragment": + def on(self, type_condition: DSLType) -> Self: """Provides the GraphQL type of this fragment. :param type_condition: the provided type @@ -1506,7 +1512,7 @@ def executable_ast(self) -> FragmentDefinitionNode: directives=self.directives_ast, ) - def is_valid_directive(self, directive: "DSLDirective") -> bool: + def is_valid_directive(self, directive: DSLDirective) -> bool: """Check if directive is valid for Fragment Definition locations.""" return ( DirectiveLocation.FRAGMENT_DEFINITION in directive.directive_def.locations From 408e1f171261fa45956d77bb45206534fa6bebc1 Mon Sep 17 00:00:00 2001 From: Leszek Hanusz Date: Fri, 5 Sep 2025 17:32:51 +0200 Subject: [PATCH 4/6] Moving gql_dsl method at the end of the file --- gql/dsl.py | 110 ++++++++++++++++++++++++++--------------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/gql/dsl.py b/gql/dsl.py index a1a1b69b..64707028 100644 --- a/gql/dsl.py +++ b/gql/dsl.py @@ -236,61 +236,6 @@ def ast_from_value(value: Any, type_: GraphQLInputType) -> Optional[ValueNode]: raise TypeError(f"Unexpected input type: {inspect(type_)}.") -def dsl_gql( - *operations: "DSLExecutable", **operations_with_name: "DSLExecutable" -) -> GraphQLRequest: - r"""Given arguments instances of :class:`DSLExecutable` - containing GraphQL operations or fragments, - generate a Document which can be executed later in a - gql client or a gql session. - - Similar to the :func:`gql.gql` function but instead of parsing a python - string to describe the request, we are using operations which have been generated - dynamically using instances of :class:`DSLField`, generated - by instances of :class:`DSLType` which themselves originated from - a :class:`DSLSchema` class. - - :param \*operations: the GraphQL operations and fragments - :type \*operations: DSLQuery, DSLMutation, DSLSubscription, DSLFragment - :param \**operations_with_name: the GraphQL operations with an operation name - :type \**operations_with_name: DSLQuery, DSLMutation, DSLSubscription - - :return: a :class:`GraphQLRequest ` - which can be later executed or subscribed by a - :class:`Client `, by an - :class:`async session ` or by a - :class:`sync session ` - - :raises TypeError: if an argument is not an instance of :class:`DSLExecutable` - :raises AttributeError: if a type has not been provided in a :class:`DSLFragment` - """ - - # Concatenate operations without and with name - all_operations: Tuple["DSLExecutable", ...] = ( - *operations, - *(operation for operation in operations_with_name.values()), - ) - - # Set the operation name - for name, operation in operations_with_name.items(): - operation.name = name - - # Check the type - for operation in all_operations: - if not isinstance(operation, DSLExecutable): - raise TypeError( - "Operations should be instances of DSLExecutable " - "(DSLQuery, DSLMutation, DSLSubscription or DSLFragment).\n" - f"Received: {type(operation)}." - ) - - document = DocumentNode( - definitions=[operation.executable_ast for operation in all_operations] - ) - - return GraphQLRequest(document) - - class DSLSchema: """The DSLSchema is the root of the DSL code. @@ -1520,3 +1465,58 @@ def is_valid_directive(self, directive: DSLDirective) -> bool: def __repr__(self) -> str: return f"<{self.__class__.__name__} {self.name!s}>" + + +def dsl_gql( + *operations: DSLExecutable, **operations_with_name: DSLExecutable +) -> GraphQLRequest: + r"""Given arguments instances of :class:`DSLExecutable` + containing GraphQL operations or fragments, + generate a Document which can be executed later in a + gql client or a gql session. + + Similar to the :func:`gql.gql` function but instead of parsing a python + string to describe the request, we are using operations which have been generated + dynamically using instances of :class:`DSLField`, generated + by instances of :class:`DSLType` which themselves originated from + a :class:`DSLSchema` class. + + :param \*operations: the GraphQL operations and fragments + :type \*operations: DSLQuery, DSLMutation, DSLSubscription, DSLFragment + :param \**operations_with_name: the GraphQL operations with an operation name + :type \**operations_with_name: DSLQuery, DSLMutation, DSLSubscription + + :return: a :class:`GraphQLRequest ` + which can be later executed or subscribed by a + :class:`Client `, by an + :class:`async session ` or by a + :class:`sync session ` + + :raises TypeError: if an argument is not an instance of :class:`DSLExecutable` + :raises AttributeError: if a type has not been provided in a :class:`DSLFragment` + """ + + # Concatenate operations without and with name + all_operations: Tuple["DSLExecutable", ...] = ( + *operations, + *(operation for operation in operations_with_name.values()), + ) + + # Set the operation name + for name, operation in operations_with_name.items(): + operation.name = name + + # Check the type + for operation in all_operations: + if not isinstance(operation, DSLExecutable): + raise TypeError( + "Operations should be instances of DSLExecutable " + "(DSLQuery, DSLMutation, DSLSubscription or DSLFragment).\n" + f"Received: {type(operation)}." + ) + + document = DocumentNode( + definitions=[operation.executable_ast for operation in all_operations] + ) + + return GraphQLRequest(document) From 00b9f254125f4792a5f960b89ed31e8ee9645d72 Mon Sep 17 00:00:00 2001 From: Leszek Hanusz Date: Fri, 5 Sep 2025 17:37:01 +0200 Subject: [PATCH 5/6] Moving DSLSelectable and DSLSelectableWithAlias up, DSLSelector down --- gql/dsl.py | 270 ++++++++++++++++++++++++++--------------------------- 1 file changed, 135 insertions(+), 135 deletions(-) diff --git a/gql/dsl.py b/gql/dsl.py index 64707028..27aa0e51 100644 --- a/gql/dsl.py +++ b/gql/dsl.py @@ -329,78 +329,6 @@ def __getattr__(self, name: str) -> "DSLType": return DSLType(type_def, self) -class DSLSelector(ABC): - """DSLSelector is an abstract class which defines the - :meth:`select ` method to select - children fields in the query. - - Inherited by - :class:`DSLRootFieldSelector `, - :class:`DSLFieldSelector ` - :class:`DSLFragmentSelector ` - """ - - selection_set: SelectionSetNode - - def __init__( - self, - *fields: "DSLSelectable", - **fields_with_alias: "DSLSelectableWithAlias", - ): - """:meta private:""" - self.selection_set = SelectionSetNode(selections=()) - - if fields or fields_with_alias: - self.select(*fields, **fields_with_alias) - - @abstractmethod - def is_valid_field(self, field: "DSLSelectable") -> bool: - raise NotImplementedError( - "Any DSLSelector subclass must have a is_valid_field method" - ) # pragma: no cover - - def select( - self, - *fields: "DSLSelectable", - **fields_with_alias: "DSLSelectableWithAlias", - ) -> Any: - r"""Select the fields which should be added. - - :param \*fields: fields or fragments - :type \*fields: DSLSelectable - :param \**fields_with_alias: fields or fragments with alias as key - :type \**fields_with_alias: DSLSelectable - - :raises TypeError: if an argument is not an instance of :class:`DSLSelectable` - :raises graphql.error.GraphQLError: if an argument is not a valid field - """ - # Concatenate fields without and with alias - added_fields: Tuple["DSLSelectable", ...] = DSLField.get_aliased_fields( - fields, fields_with_alias - ) - - # Check that each field is valid - for field in added_fields: - if not isinstance(field, DSLSelectable): - raise TypeError( - "Fields should be instances of DSLSelectable. " - f"Received: {type(field)}" - ) - - if not self.is_valid_field(field): - raise GraphQLError(f"Invalid field for {self!r}: {field!r}") - - # Get a list of AST Nodes for each added field - added_selections: Tuple[ - Union[FieldNode, InlineFragmentNode, FragmentSpreadNode], ... - ] = tuple(field.ast_field for field in added_fields) - - # Update the current selection list with new selections - self.selection_set.selections = self.selection_set.selections + added_selections - - log.debug(f"Added fields: {added_fields} in {self!r}") - - class DSLDirective: """The DSLDirective represents a GraphQL directive for the DSL code. @@ -612,6 +540,138 @@ def directives_ast(self) -> Tuple[DirectiveNode, ...]: return tuple(directive.ast_directive for directive in self._directives) +class DSLSelectable(DSLDirectable): + """DSLSelectable is an abstract class which indicates that + the subclasses can be used as arguments of the + :meth:`select ` method. + + Inherited by + :class:`DSLField `, + :class:`DSLFragment ` + :class:`DSLInlineFragment ` + """ + + ast_field: Union[FieldNode, InlineFragmentNode, FragmentSpreadNode] + + @staticmethod + def get_aliased_fields( + fields: Iterable["DSLSelectable"], + fields_with_alias: Dict[str, "DSLSelectableWithAlias"], + ) -> Tuple["DSLSelectable", ...]: + """ + :meta private: + + Concatenate all the fields (with or without alias) in a Tuple. + + Set the requested alias for the fields with alias. + """ + + return ( + *fields, + *(field.alias(alias) for alias, field in fields_with_alias.items()), + ) + + def __str__(self) -> str: + return print_ast(self.ast_field) + + +class DSLSelectableWithAlias(DSLSelectable): + """DSLSelectableWithAlias is an abstract class which indicates that + the subclasses can be selected with an alias. + """ + + ast_field: FieldNode + + def alias(self, alias: str) -> Self: + """Set an alias + + .. note:: + You can also pass the alias directly at the + :meth:`select ` method. + :code:`ds.Query.human.select(my_name=ds.Character.name)` is equivalent to: + :code:`ds.Query.human.select(ds.Character.name.alias("my_name"))` + + :param alias: the alias + :type alias: str + :return: itself + """ + + self.ast_field.alias = NameNode(value=alias) + return self + + +class DSLSelector(ABC): + """DSLSelector is an abstract class which defines the + :meth:`select ` method to select + children fields in the query. + + Inherited by + :class:`DSLRootFieldSelector `, + :class:`DSLFieldSelector ` + :class:`DSLFragmentSelector ` + """ + + selection_set: SelectionSetNode + + def __init__( + self, + *fields: DSLSelectable, + **fields_with_alias: DSLSelectableWithAlias, + ): + """:meta private:""" + self.selection_set = SelectionSetNode(selections=()) + + if fields or fields_with_alias: + self.select(*fields, **fields_with_alias) + + @abstractmethod + def is_valid_field(self, field: DSLSelectable) -> bool: + raise NotImplementedError( + "Any DSLSelector subclass must have a is_valid_field method" + ) # pragma: no cover + + def select( + self, + *fields: DSLSelectable, + **fields_with_alias: DSLSelectableWithAlias, + ) -> Any: + r"""Select the fields which should be added. + + :param \*fields: fields or fragments + :type \*fields: DSLSelectable + :param \**fields_with_alias: fields or fragments with alias as key + :type \**fields_with_alias: DSLSelectable + + :raises TypeError: if an argument is not an instance of :class:`DSLSelectable` + :raises graphql.error.GraphQLError: if an argument is not a valid field + """ + # Concatenate fields without and with alias + added_fields: Tuple[DSLSelectable, ...] = DSLField.get_aliased_fields( + fields, fields_with_alias + ) + + # Check that each field is valid + for field in added_fields: + if not isinstance(field, DSLSelectable): + raise TypeError( + "Fields should be instances of DSLSelectable. " + f"Received: {type(field)}" + ) + + if not self.is_valid_field(field): + raise GraphQLError(f"Invalid field for {self!r}: {field!r}") + + # Get a list of AST Nodes for each added field + added_selections: Tuple[ + Union[FieldNode, InlineFragmentNode, FragmentSpreadNode], ... + ] = tuple(field.ast_field for field in added_fields) + + # Update the current selection list with new selections + self.selection_set.selections = self.selection_set.selections + added_selections + + log.debug(f"Added fields: {added_fields} in {self!r}") + + class DSLExecutable(DSLSelector, DSLDirectable): """Interface for the root elements which can be executed in the :func:`dsl_gql ` function @@ -635,8 +695,8 @@ def executable_ast(self): def __init__( self, - *fields: "DSLSelectable", - **fields_with_alias: "DSLSelectableWithAlias", + *fields: DSLSelectable, + **fields_with_alias: DSLSelectableWithAlias, ): r"""Given arguments of type :class:`DSLSelectable` containing GraphQL requests, generate an operation which can be converted to a Document @@ -673,7 +733,7 @@ class DSLRootFieldSelector(DSLSelector): :class:`DSLOperation ` """ - def is_valid_field(self, field: "DSLSelectable") -> bool: + def is_valid_field(self, field: DSLSelectable) -> bool: """Check that a field is valid for a root field. For operations, the fields arguments should be fields of root GraphQL types @@ -940,41 +1000,6 @@ def __repr__(self) -> str: return f"<{self.__class__.__name__} {self._type!r}>" -class DSLSelectable(DSLDirectable): - """DSLSelectable is an abstract class which indicates that - the subclasses can be used as arguments of the - :meth:`select ` method. - - Inherited by - :class:`DSLField `, - :class:`DSLFragment ` - :class:`DSLInlineFragment ` - """ - - ast_field: Union[FieldNode, InlineFragmentNode, FragmentSpreadNode] - - @staticmethod - def get_aliased_fields( - fields: Iterable["DSLSelectable"], - fields_with_alias: Dict[str, "DSLSelectableWithAlias"], - ) -> Tuple["DSLSelectable", ...]: - """ - :meta private: - - Concatenate all the fields (with or without alias) in a Tuple. - - Set the requested alias for the fields with alias. - """ - - return ( - *fields, - *(field.alias(alias) for alias, field in fields_with_alias.items()), - ) - - def __str__(self) -> str: - return print_ast(self.ast_field) - - class DSLFragmentSelector(DSLSelector): """Class used to define the :meth:`is_valid_field ` method @@ -1041,31 +1066,6 @@ def is_valid_field(self, field: DSLSelectable) -> bool: return False -class DSLSelectableWithAlias(DSLSelectable): - """DSLSelectableWithAlias is an abstract class which indicates that - the subclasses can be selected with an alias. - """ - - ast_field: FieldNode - - def alias(self, alias: str) -> Self: - """Set an alias - - .. note:: - You can also pass the alias directly at the - :meth:`select ` method. - :code:`ds.Query.human.select(my_name=ds.Character.name)` is equivalent to: - :code:`ds.Query.human.select(ds.Character.name.alias("my_name"))` - - :param alias: the alias - :type alias: str - :return: itself - """ - - self.ast_field.alias = NameNode(value=alias) - return self - - class DSLField(DSLSelectableWithAlias, DSLFieldSelector): """The DSLField represents a GraphQL field for the DSL code. From 645d2b3b360c9ee2da063c58e70498cde5de77b3 Mon Sep 17 00:00:00 2001 From: Leszek Hanusz Date: Fri, 5 Sep 2025 23:24:03 +0200 Subject: [PATCH 6/6] Removing another non-necessary quotes --- gql/dsl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gql/dsl.py b/gql/dsl.py index 27aa0e51..2dd98d31 100644 --- a/gql/dsl.py +++ b/gql/dsl.py @@ -1497,7 +1497,7 @@ def dsl_gql( """ # Concatenate operations without and with name - all_operations: Tuple["DSLExecutable", ...] = ( + all_operations: Tuple[DSLExecutable, ...] = ( *operations, *(operation for operation in operations_with_name.values()), )