From f0ca827cbd7ee33af470d8edad9fc0b74f03f1be Mon Sep 17 00:00:00 2001 From: Karl Fischer Date: Wed, 18 Jan 2023 10:23:19 +0100 Subject: [PATCH 1/5] add naive support for mutations #71 --- qenerate/core/preprocessor.py | 4 +- tests/core/preprocessor/queries/mutation.gql | 2 +- tests/core/test_preprocessor.py | 11 ++- .../definitions/github/comment_mutation.gql | 14 +++ .../github/comment_mutation.py.txt | 97 +++++++++++++++++++ tests/plugins/test_generate.py | 1 + 6 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 tests/generator/definitions/github/comment_mutation.gql create mode 100644 tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt diff --git a/qenerate/core/preprocessor.py b/qenerate/core/preprocessor.py index fbf801b..6555751 100644 --- a/qenerate/core/preprocessor.py +++ b/qenerate/core/preprocessor.py @@ -79,12 +79,12 @@ def enter_operation_definition(self, node: OperationDefinitionNode, *_): body = self._node_body(node) name = self._node_name(node) - if node.operation != OperationType.QUERY: + if node.operation not in (OperationType.QUERY, OperationType.MUTATION): # TODO: logger # TODO: raise print( "[WARNING] Skipping operation definition because" - f" it is not a query: \n{body}" + f" it is neither a query nor a mutation: \n{body}" ) return diff --git a/tests/core/preprocessor/queries/mutation.gql b/tests/core/preprocessor/queries/mutation.gql index 95dbb27..4ee3d17 100644 --- a/tests/core/preprocessor/queries/mutation.gql +++ b/tests/core/preprocessor/queries/mutation.gql @@ -1,5 +1,5 @@ # qenerate: plugin=test -# This should be ignored by qenerate + mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { createReview(episode: $ep, review: $review) { stars diff --git a/tests/core/test_preprocessor.py b/tests/core/test_preprocessor.py index da997a9..e1daca8 100644 --- a/tests/core/test_preprocessor.py +++ b/tests/core/test_preprocessor.py @@ -59,7 +59,16 @@ def normalize_definition(definition: str) -> str: # Test a file containing a mutation [ Path("tests/core/preprocessor/queries/mutation.gql"), - [], + [ + GQLDefinition( + feature_flags=FeatureFlags(plugin="test"), + kind=GQLDefinitionType.QUERY, + name="CreateReviewForEpisode", + definition="mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { createReview(episode: $ep, review: $review) { stars commentary } }", + fragment_dependencies=set(), + source_file="", # adjusted in test + ) + ], ], # Test a file containing a single fragment [ diff --git a/tests/generator/definitions/github/comment_mutation.gql b/tests/generator/definitions/github/comment_mutation.gql new file mode 100644 index 0000000..00817b5 --- /dev/null +++ b/tests/generator/definitions/github/comment_mutation.gql @@ -0,0 +1,14 @@ +mutation AddComment { + addComment(input: {subjectId: "", body: ""}) { + subject { + ... on Topic { + id + name + } + ... on User { + id + email + } + } + } +} diff --git a/tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt b/tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt new file mode 100644 index 0000000..07704ce --- /dev/null +++ b/tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt @@ -0,0 +1,97 @@ +""" +Generated by qenerate plugin=pydantic_v1. DO NOT MODIFY MANUALLY! +""" +from collections.abc import Callable # noqa: F401 # pylint: disable=W0611 +from datetime import datetime # noqa: F401 # pylint: disable=W0611 +from enum import Enum # noqa: F401 # pylint: disable=W0611 +from typing import ( # noqa: F401 # pylint: disable=W0611 + Any, + Optional, + Union, +) + +from pydantic import ( # noqa: F401 # pylint: disable=W0611 + BaseModel, + Extra, + Field, + Json, +) + + +DEFINITION = """ +mutation AddComment { + addComment(input: {subjectId: "", body: ""}) { + subject { + ... on Topic { + id + name + } + ... on User { + id + email + } + } + } +} + +""" + + +class Node(BaseModel): + + class Config: + smart_union = True + extra = Extra.forbid + + +class Topic(Node): + q_id: str = Field(..., alias="id") + name: str = Field(..., alias="name") + + class Config: + smart_union = True + extra = Extra.forbid + + +class User(Node): + q_id: str = Field(..., alias="id") + email: str = Field(..., alias="email") + + class Config: + smart_union = True + extra = Extra.forbid + + +class AddCommentPayload(BaseModel): + subject: Optional[Union[Topic, User, Node]] = Field(..., alias="subject") + + class Config: + smart_union = True + extra = Extra.forbid + + +class AddCommentQueryData(BaseModel): + add_comment: Optional[AddCommentPayload] = Field(..., alias="addComment") + + class Config: + smart_union = True + extra = Extra.forbid + + +def query(query_func: Callable, **kwargs: Any) -> AddCommentQueryData: + """ + This is a convenience function which queries and parses the data into + concrete types. It should be compatible with most GQL clients. + You do not have to use it to consume the generated data classes. + Alternatively, you can also mime and alternate the behavior + of this function in the caller. + + Parameters: + query_func (Callable): Function which queries your GQL Server + kwargs: optional arguments that will be passed to the query function + + Returns: + AddCommentQueryData: queried data parsed into generated classes + """ + raw_data: dict[Any, Any] = query_func(DEFINITION, **kwargs) + return AddCommentQueryData(**raw_data) diff --git a/tests/plugins/test_generate.py b/tests/plugins/test_generate.py index 0cbb419..db8edde 100644 --- a/tests/plugins/test_generate.py +++ b/tests/plugins/test_generate.py @@ -93,6 +93,7 @@ class Schema(Enum): { "invitations_enum": GQLDefinitionType.QUERY, "issues_datetime_html": GQLDefinitionType.QUERY, + "comment_mutation": GQLDefinitionType.QUERY, }, {}, Schema.GITHUB, From 491c2f03eb1c22616f183e01f4f5a08d86d85729 Mon Sep 17 00:00:00 2001 From: Karl Fischer Date: Tue, 21 Feb 2023 23:36:16 +0100 Subject: [PATCH 2/5] adjust test case --- tests/core/test_preprocessor.py | 2 +- tests/generator/definitions/github/comment_mutation.gql | 4 ++-- .../expected/pydantic_v1/github/comment_mutation.py.txt | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/core/test_preprocessor.py b/tests/core/test_preprocessor.py index e1daca8..dff6dda 100644 --- a/tests/core/test_preprocessor.py +++ b/tests/core/test_preprocessor.py @@ -67,7 +67,7 @@ def normalize_definition(definition: str) -> str: definition="mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { createReview(episode: $ep, review: $review) { stars commentary } }", fragment_dependencies=set(), source_file="", # adjusted in test - ) + ), ], ], # Test a file containing a single fragment diff --git a/tests/generator/definitions/github/comment_mutation.gql b/tests/generator/definitions/github/comment_mutation.gql index 00817b5..9003fa7 100644 --- a/tests/generator/definitions/github/comment_mutation.gql +++ b/tests/generator/definitions/github/comment_mutation.gql @@ -1,5 +1,5 @@ -mutation AddComment { - addComment(input: {subjectId: "", body: ""}) { +mutation AddComment($body: String = "", $subjectId: ID = "") { + addComment(input: {subjectId: $subjectId, body: $body}) { subject { ... on Topic { id diff --git a/tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt b/tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt index 07704ce..76a2c88 100644 --- a/tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt +++ b/tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt @@ -19,8 +19,8 @@ from pydantic import ( # noqa: F401 # pylint: disable=W0611 DEFINITION = """ -mutation AddComment { - addComment(input: {subjectId: "", body: ""}) { +mutation AddComment($body: String = "", $subjectId: ID = "") { + addComment(input: {subjectId: $subjectId, body: $body}) { subject { ... on Topic { id From 9523c3212bdef5b18081da80af1905855a9c8863 Mon Sep 17 00:00:00 2001 From: Karl Fischer Date: Wed, 22 Feb 2023 00:37:01 +0100 Subject: [PATCH 3/5] distinguish between query and mutation --- qenerate/core/code_command.py | 2 +- qenerate/core/plugin.py | 2 +- qenerate/core/preprocessor.py | 31 ++++++++---- qenerate/plugins/pydantic_v1/plugin.py | 50 ++++++++++++++----- qenerate/plugins/pydantic_v1/typed_ast.py | 9 +++- tests/core/test_code_command.py | 2 +- tests/core/test_preprocessor.py | 2 +- .../github/comment_mutation.py.txt | 19 +++---- tests/plugins/test_generate.py | 14 +++--- 9 files changed, 86 insertions(+), 45 deletions(-) diff --git a/qenerate/core/code_command.py b/qenerate/core/code_command.py index 1a700ff..f9328ed 100644 --- a/qenerate/core/code_command.py +++ b/qenerate/core/code_command.py @@ -92,7 +92,7 @@ def generate_code(self, introspection_file_path: str, dir: str): schema=schema, ) - rendered_queries = plugin.generate_queries( + rendered_queries = plugin.generate_operations( definitions=queries_by_plugin[plugin_name], fragments=rendered_fragments, schema=schema, diff --git a/qenerate/core/plugin.py b/qenerate/core/plugin.py index 9b8939d..797da4a 100644 --- a/qenerate/core/plugin.py +++ b/qenerate/core/plugin.py @@ -24,7 +24,7 @@ class Fragment(GeneratedFile): class Plugin: - def generate_queries( + def generate_operations( self, definitions: list[GQLDefinition], schema: GraphQLSchema, diff --git a/qenerate/core/preprocessor.py b/qenerate/core/preprocessor.py index 6555751..b75727c 100644 --- a/qenerate/core/preprocessor.py +++ b/qenerate/core/preprocessor.py @@ -28,6 +28,7 @@ def __init__(self, message: str): class GQLDefinitionType(Enum): QUERY = 1 FRAGMENT = 2 + MUTATION = 3 @dataclass @@ -79,23 +80,31 @@ def enter_operation_definition(self, node: OperationDefinitionNode, *_): body = self._node_body(node) name = self._node_name(node) - if node.operation not in (OperationType.QUERY, OperationType.MUTATION): + if node.operation == OperationType.QUERY: + definition = GQLDefinition( + kind=GQLDefinitionType.QUERY, + definition=body, + source_file=self._source_file_path, + feature_flags=self._feature_flags, + fragment_dependencies=set(), + name=name, + ) + elif node.operation == OperationType.MUTATION: + definition = GQLDefinition( + kind=GQLDefinitionType.MUTATION, + definition=body, + source_file=self._source_file_path, + feature_flags=self._feature_flags, + fragment_dependencies=set(), + name=name, + ) + else: # TODO: logger - # TODO: raise print( "[WARNING] Skipping operation definition because" f" it is neither a query nor a mutation: \n{body}" ) return - - definition = GQLDefinition( - kind=GQLDefinitionType.QUERY, - definition=body, - source_file=self._source_file_path, - feature_flags=self._feature_flags, - fragment_dependencies=set(), - name=name, - ) self._stack.append(definition) def leave_operation_definition(self, *_): diff --git a/qenerate/plugins/pydantic_v1/plugin.py b/qenerate/plugins/pydantic_v1/plugin.py index 5480431..f574e2e 100644 --- a/qenerate/plugins/pydantic_v1/plugin.py +++ b/qenerate/plugins/pydantic_v1/plugin.py @@ -33,7 +33,7 @@ ParsedClassNode, ) from qenerate.core.feature_flag_parser import NamingCollisionStrategy, FeatureFlags -from qenerate.core.preprocessor import GQLDefinition +from qenerate.core.preprocessor import GQLDefinition, GQLDefinitionType from qenerate.plugins.pydantic_v1.mapper import ( graphql_class_name_to_python, @@ -66,7 +66,7 @@ ) -def convenience_function(cls: str) -> str: +def query_convenience_function(cls: str) -> str: return f""" def query(query_func: Callable, **kwargs: Any) -> {cls}: {INDENT}\"\"\" @@ -88,6 +88,29 @@ def query(query_func: Callable, **kwargs: Any) -> {cls}: """ +def mutation_convenience_function(cls: str) -> str: + return f""" +def mutate(mutation_func: Callable, **kwargs: Any) -> {cls}: +{INDENT}\"\"\" +{INDENT}This is a convenience function which executes a mutation and parses the response +{INDENT}into concrete types. It should be compatible with most GQL clients. +{INDENT}You do not have to use it to consume the generated data classes. +{INDENT}Alternatively, you can also mime and alternate the behavior +{INDENT}of this function in the caller. + +{INDENT}Parameters: +{INDENT}{INDENT}mutation_func (Callable): Function which executes the mutation. +{INDENT}{INDENT}kwargs: Arguments that will be passed to the query function. +{INDENT}{INDENT}{INDENT}This must include the mutation parameters. + +{INDENT}Returns: +{INDENT}{INDENT}{cls}: mutation response parsed into generated classes +{INDENT}\"\"\" +{INDENT}raw_data: dict[Any, Any] = mutation_func(DEFINITION, **kwargs) +{INDENT}return {cls}(**raw_data) +""" + + class PydanticV1Error(Exception): pass @@ -97,7 +120,7 @@ def __init__( self, schema: GraphQLSchema, type_info: TypeInfo, - definition: str, + definition: GQLDefinition, feature_flags: FeatureFlags, ): Visitor.__init__(self) @@ -140,6 +163,7 @@ def enter_operation_definition(self, node: OperationDefinitionNode, *_): current = ParsedOperationNode( parent=self.parent, fields=[], + operation_type=self.definition.kind, parsed_type=ParsedFieldType( unwrapped_python_type=node.name.value, wrapped_python_type=node.name.value, @@ -266,9 +290,9 @@ def _to_python_type(self, graphql_type: GraphQLOutputType) -> str: class QueryParser: @staticmethod def parse( - definition: str, schema: GraphQLSchema, feature_flags: FeatureFlags + definition: GQLDefinition, schema: GraphQLSchema, feature_flags: FeatureFlags ) -> ParsedNode: - document_ast = parse(definition) + document_ast = parse(definition.definition) type_info = TypeInfo(schema) visitor = FieldToTypeMatcherVisitor( schema=schema, @@ -339,9 +363,8 @@ def generate_fragments( result += fragment_imports qf = definition.source_file parser = QueryParser() - fragment_definition = definition.definition ast = parser.parse( - definition=fragment_definition, + definition=definition, schema=schema, feature_flags=definition.feature_flags, ) @@ -400,7 +423,7 @@ def _assemble_definition( ) return ans - def generate_queries( + def generate_operations( self, definitions: list[GQLDefinition], schema: GraphQLSchema, @@ -433,17 +456,18 @@ def generate_queries( ) result += 'DEFINITION = """\n' f"{assembled_definition}" '\n"""' parser = QueryParser() - query = definition.definition ast = parser.parse( - definition=query, + definition=definition, schema=schema, feature_flags=definition.feature_flags, ) result += self._traverse(ast) result += "\n\n" - result += convenience_function( - cls=f"{ast.fields[0].parsed_type.unwrapped_python_type}QueryData" - ) + cls = ast.fields[0].parsed_type.unwrapped_python_type + if definition.kind == GQLDefinitionType.QUERY: + result += query_convenience_function(cls=f"{cls}QueryData") + else: + result += mutation_convenience_function(cls=f"{cls}MutationResponse") generated_files.append( GeneratedFile(file=qf.with_suffix(".py"), content=result) ) diff --git a/qenerate/plugins/pydantic_v1/typed_ast.py b/qenerate/plugins/pydantic_v1/typed_ast.py index 6443b8f..5b3d942 100644 --- a/qenerate/plugins/pydantic_v1/typed_ast.py +++ b/qenerate/plugins/pydantic_v1/typed_ast.py @@ -2,6 +2,8 @@ from dataclasses import dataclass from typing import Any, Optional +from qenerate.core.preprocessor import GQLDefinitionType + INDENT = " " @@ -155,10 +157,15 @@ def field_type(self) -> str: @dataclass class ParsedOperationNode(ParsedNode): + operation_type: GQLDefinitionType + def class_code_string(self) -> str: lines = ["\n\n"] + class_suffix = "QueryData" + if self.operation_type == GQLDefinitionType.MUTATION: + class_suffix = "MutationResponse" lines.append( - f"class {self.parsed_type.unwrapped_python_type}QueryData(BaseModel):" + f"class {self.parsed_type.unwrapped_python_type}{class_suffix}(BaseModel):" ) for field in self.fields: if isinstance(field, ParsedClassNode): diff --git a/tests/core/test_code_command.py b/tests/core/test_code_command.py index 15396b6..c1ea2b1 100644 --- a/tests/core/test_code_command.py +++ b/tests/core/test_code_command.py @@ -20,7 +20,7 @@ def generate_fragments( ) -> list[Fragment]: return [] - def generate_queries( + def generate_operations( self, definitions: list[GQLDefinition], fragments: list[Fragment], diff --git a/tests/core/test_preprocessor.py b/tests/core/test_preprocessor.py index dff6dda..776f002 100644 --- a/tests/core/test_preprocessor.py +++ b/tests/core/test_preprocessor.py @@ -62,7 +62,7 @@ def normalize_definition(definition: str) -> str: [ GQLDefinition( feature_flags=FeatureFlags(plugin="test"), - kind=GQLDefinitionType.QUERY, + kind=GQLDefinitionType.MUTATION, name="CreateReviewForEpisode", definition="mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { createReview(episode: $ep, review: $review) { stars commentary } }", fragment_dependencies=set(), diff --git a/tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt b/tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt index 76a2c88..9b7c793 100644 --- a/tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt +++ b/tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt @@ -70,7 +70,7 @@ class AddCommentPayload(BaseModel): extra = Extra.forbid -class AddCommentQueryData(BaseModel): +class AddCommentMutationResponse(BaseModel): add_comment: Optional[AddCommentPayload] = Field(..., alias="addComment") class Config: @@ -78,20 +78,21 @@ class AddCommentQueryData(BaseModel): extra = Extra.forbid -def query(query_func: Callable, **kwargs: Any) -> AddCommentQueryData: +def mutate(mutation_func: Callable, **kwargs: Any) -> AddCommentMutationResponse: """ - This is a convenience function which queries and parses the data into - concrete types. It should be compatible with most GQL clients. + This is a convenience function which executes a mutation and parses the response + into concrete types. It should be compatible with most GQL clients. You do not have to use it to consume the generated data classes. Alternatively, you can also mime and alternate the behavior of this function in the caller. Parameters: - query_func (Callable): Function which queries your GQL Server - kwargs: optional arguments that will be passed to the query function + mutation_func (Callable): Function which executes the mutation. + kwargs: Arguments that will be passed to the query function. + This must include the mutation parameters. Returns: - AddCommentQueryData: queried data parsed into generated classes + AddCommentMutationResponse: mutation response parsed into generated classes """ - raw_data: dict[Any, Any] = query_func(DEFINITION, **kwargs) - return AddCommentQueryData(**raw_data) + raw_data: dict[Any, Any] = mutation_func(DEFINITION, **kwargs) + return AddCommentMutationResponse(**raw_data) diff --git a/tests/plugins/test_generate.py b/tests/plugins/test_generate.py index db8edde..18f8fbf 100644 --- a/tests/plugins/test_generate.py +++ b/tests/plugins/test_generate.py @@ -93,7 +93,7 @@ class Schema(Enum): { "invitations_enum": GQLDefinitionType.QUERY, "issues_datetime_html": GQLDefinitionType.QUERY, - "comment_mutation": GQLDefinitionType.QUERY, + "comment_mutation": GQLDefinitionType.MUTATION, }, {}, Schema.GITHUB, @@ -117,7 +117,7 @@ def test_rendering( app_interface_schema if use_schema == Schema.APP_INTERFACE else github_schema ) fragment_definitions = [] - query_definitions = [] + operation_definitions = [] for source_file in Path(f"tests/generator/definitions/{case}").glob("**/*"): file_id = source_file.with_suffix("").name with open(source_file, "r") as f: @@ -136,10 +136,10 @@ def test_rendering( kind=kind, name=file_id, ) - if kind == GQLDefinitionType.QUERY: - query_definitions.append(definition) - else: + if kind == GQLDefinitionType.FRAGMENT: fragment_definitions.append(definition) + else: + operation_definitions.append(definition) plugin = plugins[plugin_name] @@ -159,8 +159,8 @@ def test_rendering( ) generated_files.extend( - plugin.generate_queries( - definitions=query_definitions, + plugin.generate_operations( + definitions=operation_definitions, fragments=fragments, schema=schema, ) From 5d989afbdf376986d96bf145c69c86274b155786 Mon Sep 17 00:00:00 2001 From: Karl Fischer Date: Wed, 22 Feb 2023 00:39:15 +0100 Subject: [PATCH 4/5] fix typo --- qenerate/plugins/pydantic_v1/plugin.py | 2 +- .../expected/pydantic_v1/github/comment_mutation.py.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qenerate/plugins/pydantic_v1/plugin.py b/qenerate/plugins/pydantic_v1/plugin.py index f574e2e..d910d24 100644 --- a/qenerate/plugins/pydantic_v1/plugin.py +++ b/qenerate/plugins/pydantic_v1/plugin.py @@ -100,7 +100,7 @@ def mutate(mutation_func: Callable, **kwargs: Any) -> {cls}: {INDENT}Parameters: {INDENT}{INDENT}mutation_func (Callable): Function which executes the mutation. -{INDENT}{INDENT}kwargs: Arguments that will be passed to the query function. +{INDENT}{INDENT}kwargs: Arguments that will be passed to the mutation function. {INDENT}{INDENT}{INDENT}This must include the mutation parameters. {INDENT}Returns: diff --git a/tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt b/tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt index 9b7c793..fa80299 100644 --- a/tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt +++ b/tests/generator/expected/pydantic_v1/github/comment_mutation.py.txt @@ -88,7 +88,7 @@ def mutate(mutation_func: Callable, **kwargs: Any) -> AddCommentMutationResponse Parameters: mutation_func (Callable): Function which executes the mutation. - kwargs: Arguments that will be passed to the query function. + kwargs: Arguments that will be passed to the mutation function. This must include the mutation parameters. Returns: From b9df99ba3cab454dfd1a92ec834de6b1a73dd12a Mon Sep 17 00:00:00 2001 From: Karl Fischer Date: Wed, 22 Feb 2023 15:40:53 +0100 Subject: [PATCH 5/5] Prepare release --- docs/plugins/pydantic_v1.md | 1 + pyproject.toml | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/plugins/pydantic_v1.md b/docs/plugins/pydantic_v1.md index ed404ee..75ad9b5 100644 --- a/docs/plugins/pydantic_v1.md +++ b/docs/plugins/pydantic_v1.md @@ -9,6 +9,7 @@ Supported definitions are: - `fragment` - `query` +- `mutation` (only response data structures - input data structures are still a [TODO](https://github.com/app-sre/qenerate/issues/71)) ## Opinionated Custom Scalars diff --git a/pyproject.toml b/pyproject.toml index b4ab37e..6a8f697 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "qenerate" -version = "0.4.7" +version = "0.5.0" description = "Code Generator for GraphQL Query and Fragment Data Classes" authors = [ "Red Hat - Service Delivery - AppSRE " diff --git a/setup.py b/setup.py index b013ed3..69ba1ac 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ setup_kwargs = { "name": "qenerate", - "version": "0.4.7", + "version": "0.5.0", "description": "Code Generator for GraphQL Query and Fragment Data Classes", "long_description": "Qenerate is a Code Generator for GraphQL Query and Fragment Data Classes. Documentation is at https://github.com/app-sre/qenerate .", "author": "Service Delivery - AppSRE",