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

ClientForwardRefsPlugin Error on generation #313

Open
duodecanol opened this issue Sep 13, 2024 · 5 comments
Open

ClientForwardRefsPlugin Error on generation #313

duodecanol opened this issue Sep 13, 2024 · 5 comments

Comments

@duodecanol
Copy link

Summary

  • ariadne-codegen: 0.14.0
  • python:
    • 3.12.5
    • 3.12.4
    • 3.11.2
  • import_class_name = import_class.name
    # We add the class to our set of imported in methods - these classes
    # don't need to be imported at all in the global scope.
    self.imported_in_method.add(import_class_name)
    method_def.body.insert(
    0,
    ast.ImportFrom(
    module=self.imported_classes[import_class_name],
    names=[import_class],
    level=1,
    ),
    )

Error log

Selected strategy: Strategy.CLIENT
Using schema from '....................'.
Reading queries from ''.
Using '********' as package name.
Generating package into '********'.
Using '********' as client name.
Using 'AsyncBaseClient' as base client class.
Coping base client class from '********'.
Generating enums into 'enums.py'.
Generating inputs into 'input_types.py'.
Generating fragments into 'fragments.py'.
Comments type: stable
Converting fields and arguments name to snake case.
Generating async client.
No files to copy.
Plugins to use: ariadne_codegen.contrib.no_reimports.NoReimportsPlugin,ariadne_codegen.contrib.client_forward_refs.ClientForwardRefsPlugin
================================================================================
<ast.Name object at 0x7d2e44ae0ed0> ('lineno', 'col_offset', 'end_lineno', 'end_col_offset') ('id', 'ctx')
self
Traceback (most recent call last):
  File "/workspaces/python-devpod-try/xxDev/graphqltest/.venv/bin/ariadne-codegen", line 8, in <module>
    sys.exit(main())
             ^^^^^^
  File "/workspaces/python-devpod-try/xxDev/graphqltest/.venv/lib/python3.12/site-packages/click/core.py", line 1157, in __call__
    return self.main(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/python-devpod-try/xxDev/graphqltest/.venv/lib/python3.12/site-packages/click/core.py", line 1078, in main
    rv = self.invoke(ctx)
         ^^^^^^^^^^^^^^^^
  File "/workspaces/python-devpod-try/xxDev/graphqltest/.venv/lib/python3.12/site-packages/click/core.py", line 1434, in invoke
    return ctx.invoke(self.callback, **ctx.params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/python-devpod-try/xxDev/graphqltest/.venv/lib/python3.12/site-packages/click/core.py", line 783, in invoke
    return __callback(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/python-devpod-try/xxDev/graphqltest/.venv/lib/python3.12/site-packages/ariadne_codegen/main.py", line 37, in main
    client(config_dict)
  File "/workspaces/python-devpod-try/xxDev/graphqltest/.venv/lib/python3.12/site-packages/ariadne_codegen/main.py", line 81, in client
    generated_files = package_generator.generate()
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/python-devpod-try/xxDev/graphqltest/.venv/lib/python3.12/site-packages/ariadne_codegen/client_generators/package.py", line 171, in generate
    self._generate_client()
  File "/workspaces/python-devpod-try/xxDev/graphqltest/.venv/lib/python3.12/site-packages/ariadne_codegen/client_generators/package.py", line 257, in _generate_client
    client_module = self.client_generator.generate()
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/python-devpod-try/xxDev/graphqltest/.venv/lib/python3.12/site-packages/ariadne_codegen/client_generators/client.py", line 148, in generate
    module = self.plugin_manager.generate_client_module(module)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/python-devpod-try/xxDev/graphqltest/.venv/lib/python3.12/site-packages/ariadne_codegen/plugins/manager.py", line 60, in generate_client_module
    return self._apply_plugins_on_object("generate_client_module", module)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/python-devpod-try/xxDev/graphqltest/.venv/lib/python3.12/site-packages/ariadne_codegen/plugins/manager.py", line 40, in _apply_plugins_on_object
    modified_obj = method(modified_obj, *args, **kwargs)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/workspaces/python-devpod-try/xxDev/graphqltest/.venv/lib/python3.12/site-packages/ariadne_codegen/contrib/client_forward_refs.py", line 91, in generate_client_module
    self._insert_import_statement_in_method(method_def)
  File "/workspaces/python-devpod-try/xxDev/graphqltest/.venv/lib/python3.12/site-packages/ariadne_codegen/contrib/client_forward_refs.py", line 188, in _insert_import_statement_in_method
    module=self.imported_classes[import_class_id],
           ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
KeyError: 'self'

Suggestion

import_class_name = import_class.name
# We add the class to our set of imported in methods - these classes
# don't need to be imported at all in the global scope.
self.imported_in_method.add(import_class_name)
method_def.body.insert(
0,
ast.ImportFrom(
module=self.imported_classes[import_class_name],
names=[import_class],
level=1,
),
)

        import_class_id = import_class.id
        
+        if import_class_id == "self":
+            return

        # We add the class to our set of imported in methods - these classes
        # don't need to be imported at all in the global scope.
        self.imported_in_method.add(import_class.id)
        method_def.body.insert(
            0,
            ast.ImportFrom(
                module=self.imported_classes[import_class_id],
                names=[import_class],
            ),
        )
@duodecanol
Copy link
Author

duodecanol commented Sep 13, 2024

In the above context:

print(self.imported_classes)
>>> {'AsyncBaseClient': '.async_base_client', 'UNSET': '.base_model', 'UnsetType': '.base_model', 'Upload': '.base_model', 'GraphQLField': '.base_operation'}

@bombsimon
Copy link
Contributor

bombsimon commented Sep 13, 2024

The code you're linking was changed in #306, do you have the same issue on latest main? If so, do you have a reproducible example or do you also get this on any of the two tests?

@duodecanol
Copy link
Author

The code you're linking was changed in #306, do you have the same issue on latest main? If so, do you have a reproducible example or do you also get this on any of the two tests?

The pyroject.toml below would be suffice to demonstrate the case.
Steps:

  • run ariadne-codegen without plugins
    • OK
  • run ariadne-codegen with the plugin ClientForwardRefsPlugin
    • Error
  • remove the previously generated codes and then run ariadne-codegen with the plugin ClientForwardRefsPlugin
    • Error
[project]
name = "ard-test"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
    "ariadne-codegen==0.14.0",
]
[tool.ariadne-codegen]

remote_schema_url = "https://countries.trevorblades.com"

enable_custom_operations = true

plugins = [
    "ariadne_codegen.contrib.client_forward_refs.ClientForwardRefsPlugin",
]

@bombsimon
Copy link
Contributor

Thanks. The example uses latest release (0.14.0) but I was curious about if it failed on main. I used your example and can confirm it does. However, I'm wonder if this is partly related to enable_custom_operations = true since there are no other operations, there's also no other imports so the use of the plugin isn't clear to me. However the generation shouldn't fail.

I was going to run the tests for client forward refs on Python 3.12 but noticed that they never got added to the test fixture. I opened #314 to enable the tests

@duodecanol
Copy link
Author

duodecanol commented Sep 15, 2024

Thanks. The example uses latest release (0.14.0) but I was curious about if it failed on main. I used your example and can confirm it does. However, I'm wonder if this is partly related to enable_custom_operations = true since there are no other operations, there's also no other imports so the use of the plugin isn't clear to me. However the generation shouldn't fail.

I was going to run the tests for client forward refs on Python 3.12 but noticed that they never got added to the test fixture. I opened #314 to enable the tests

I was conducting a feasibility test of this package and am new to GraphQL. My use of the plugin was driven by curiosity to understand how plugins affect the code. The issue I’ve raised is to highlight a case of execution failure, but I am not experiencing issues with using this package otherwise—it appears to be excellent.

Attached are the diff results comparing two scenarios: one without any plugins and one with the ClientForwardRefsPlugin.

To achieve this, I added some error-bypassing code to the library package, which I previously mentioned.

diff --git a/graphql_client/client.py b/graphql_client/client.py
index dc5c970..8ff011b 100644
--- a/graphql_client/client.py
+++ b/graphql_client/client.py
@@ -16,7 +16,10 @@ from graphql import (
 )
 
 from .async_base_client import AsyncBaseClient
-from .base_operation import GraphQLField
+from .typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+    from ..base_operation import GraphQLField
 
 
 def gql(q: str) -> str:
@@ -25,7 +28,10 @@ def gql(q: str) -> str:
 
 class Client(AsyncBaseClient):
     async def execute_custom_operation(
-        self, *fields: GraphQLField, operation_type: OperationType, operation_name: str
+        self,
+        *fields: "GraphQLField",
+        operation_type: OperationType,
+        operation_name: str
     ) -> Dict[str, Any]:
         selections = self._build_selection_set(fields)
         combined_variables = self._combine_variables(fields)
@@ -43,7 +49,7 @@ class Client(AsyncBaseClient):
         return self.get_data(response)
 
     def _combine_variables(
-        self, fields: Tuple[GraphQLField, ...]
+        self, fields: Tuple["GraphQLField", ...]
     ) -> Dict[str, Dict[str, Any]]:
         variables_types_combined = {}
         processed_variables_combined = {}
@@ -90,11 +96,13 @@ class Client(AsyncBaseClient):
         )
 
     def _build_selection_set(
-        self, fields: Tuple[GraphQLField, ...]
+        self, fields: Tuple["GraphQLField", ...]
     ) -> List[SelectionNode]:
         return [field.to_ast(idx) for idx, field in enumerate(fields)]
 
-    async def query(self, *fields: GraphQLField, operation_name: str) -> Dict[str, Any]:
+    async def query(
+        self, *fields: "GraphQLField", operation_name: str
+    ) -> Dict[str, Any]:
         return await self.execute_custom_operation(
             *fields, operation_type=OperationType.QUERY, operation_name=operation_name
         )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants