sgqlc icon indicating copy to clipboard operation
sgqlc copied to clipboard

operation codegen failing on boolean literals

Open worrel opened this issue 3 years ago • 5 comments

The first query (boolean literal) fails to generate with ValueError: not enough values to unpack (expected 3, got 1) while the second form succeeds:

FAILS:

query MyQuery {
   things(where: { global: { _eq: true } }) {
      id
   }
}

SUCCEEDS

query MyQuery($global: Boolean!) {
   things(where: { global: { _eq: $global } }) {
      id
   }
}

Full traceback:

Traceback (most recent call last):
  File "/Users/rory/code/github/Cogitai/sai/.venv/bin/sgqlc-codegen", line 8, in <module>
    sys.exit(main())
  File "/Users/rory/code/github/Cogitai/sai/.venv/lib/python3.9/site-packages/sgqlc/codegen/__init__.py", line 130, in main
    args.func(args)
  File "/Users/rory/code/github/Cogitai/sai/.venv/lib/python3.9/site-packages/sgqlc/codegen/operation.py", line 934, in handle_command
    gen.write()
  File "/Users/rory/code/github/Cogitai/sai/.venv/lib/python3.9/site-packages/sgqlc/codegen/operation.py", line 811, in write
    self.write_operations()
  File "/Users/rory/code/github/Cogitai/sai/.venv/lib/python3.9/site-packages/sgqlc/codegen/operation.py", line 831, in write_operations
    self.write_operation(source)
  File "/Users/rory/code/github/Cogitai/sai/.venv/lib/python3.9/site-packages/sgqlc/codegen/operation.py", line 841, in write_operation
    for kind, name, code in thing:
ValueError: not enough values to unpack (expected 3, got 1)

worrel avatar Oct 04 '21 18:10 worrel

could you confirm the graphql-core version you're using?

barbieri avatar Oct 04 '21 18:10 barbieri

I'm on 3.1.5 (also happens on 3.1.6)

worrel avatar Oct 04 '21 18:10 worrel

ok, I'll take a look, but kinda overloaded at work nowadays. If you could reproduce that with the existing examples, it would help me a lot, ex https://github.com/profusion/sgqlc/tree/master/examples/github

very likely it's in the return of the leave_* methods of GraphQLToPython.

This specific trace is https://github.com/profusion/sgqlc/blob/master/sgqlc/codegen/operation.py#L833-L841

Which should be getting the tuple returned here: https://github.com/profusion/sgqlc/blob/master/sgqlc/codegen/operation.py#L520-L527

but seems this is not the case, since it's returning a single value, not the tuple with the 3 arguments... 🤔

barbieri avatar Oct 04 '21 18:10 barbieri

@barbieri thanks for taking a look, i'll try debug further & report back!

worrel avatar Oct 04 '21 18:10 worrel

@worrel would you mind checking if it's still happening? Many fixes to handle input, maybe it was fixed?

barbieri avatar Jun 22 '22 18:06 barbieri

Hi, @barbieri . I think I'm facing the same issue.

When I run this command:

sgqlc-codegen operation my_schema ./operations/dataset.py /home/georvic/repos/datahub/datahub-web-react/src/graphql/dataset.graphql

with the following file: https://github.com/datahub-project/datahub/blob/master/datahub-web-react/src/graphql/dataset.graphql

I see the following output:

Traceback (most recent call last):
  File "/home/georvic/anaconda3/envs/datahub/bin/sgqlc-codegen", line 8, in <module>
    sys.exit(main())
  File "/home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/sgqlc/codegen/__init__.py", line 130, in main
    args.func(args)
  File "/home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/sgqlc/codegen/operation.py", line 949, in handle_command
    gen.write()
  File "/home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/sgqlc/codegen/operation.py", line 826, in write
    self.write_operations()
  File "/home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/sgqlc/codegen/operation.py", line 846, in write_operations
    self.write_operation(source)
  File "/home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/sgqlc/codegen/operation.py", line 856, in write_operation
    for kind, name, code in visit(gql, visitor):
ValueError: not enough values to unpack (expected 3, got 1)

When taking a look in the dataset.graphql file, I can see the following: https://github.com/datahub-project/datahub/blob/master/datahub-web-react/src/graphql/dataset.graphql#L114

    autoRenderAspects: aspects(input: { autoRenderOnly: true }) {
        aspectName
        payload
        renderSpec {
            displayType
            displayName
            key
        }
    }

So, it seems the same issue.

My versions are:

sgqlc==16.2 Python 3.7.16 graphql-core==3.2.3

Notes:

If I replace the true by a false, I get the following output in the python file:

_frag_auto_render_aspects = _frag.aspects(input={'autoRenderOnly': BooleanValueNode at 2402:2407}, __alias__='auto_render_aspects')

If I place a breakpoint here:

imagen

I get the following output in pdb

(Pdb) res = list(visit(gql, visitor))
(Pdb) res
['a', 'u', 't', 'o', 'R', 'e', 'n', 'd', 'e', 'r', 'O', 'n', 'l', 'y']

J0hnG4lt avatar Jun 18 '23 01:06 J0hnG4lt

hi, could you check with graphql-core==3.1.6? I bet the error is there, if that's the case I'll need to check how to make a code that works in both or just bump the minimum requirement to be that version (since it's out since september 2022, almost one year old).

barbieri avatar Jun 19 '23 18:06 barbieri

sorry, edited the last msg, it's 3.1.6 that should be tested.

barbieri avatar Jun 19 '23 18:06 barbieri

Looking at https://github.com/datahub-project/datahub/blob/master/datahub-web-react/src/graphql/dataset.graphql#L114 what calls attention is the usage of an alias (autoRenderAspects), we should be handling them correctly at https://github.com/profusion/sgqlc/blob/master/sgqlc/codegen/operation.py#L651-L671

        alias = ''
        if node.alias:
            alias = to_python_name(node.alias)
            args = list(args) + [('__alias__', alias)]

could you please check this part? Also, if you can print the kind at https://github.com/graphql-python/graphql-core/blob/main/src/graphql/language/visitor.py#L145-L153, we could see if there is something we're missing.

barbieri avatar Jun 19 '23 18:06 barbieri

Hi, @barbieri . Thanks for taking a look. Yes, it also happens with that version:

imagen

For this version, I don't see the get_enter_leave_for_kind function.

J0hnG4lt avatar Jun 20 '23 22:06 J0hnG4lt

If I use the version I tested originally, I do find the function. After placing a print call, I get the following: imagen

So, the last element before the exception is: boolean_value

If I place a breakpoint here using an if:

imagen

, I get the following:

(Pdb) enter_leave
EnterLeaveVisitor(enter=None, leave=<bound method GraphQLToPython.leave_boolean_value of <sgqlc.codegen.operation.GraphQLToPython object at 0x7eff0170abd0>>)
(Pdb) 

and these are all the steps shown in the debugger until the exception occurs:

Click here to expand all the pdb steps (just pressing n until the exception appears)
(datahub) georvic@georvic-IdeaPad-3-15ITL6:~/repos/datahub-metadata$ sgqlc-codegen operation my_schema ./operations/dataset.py /home/georvic/repos/datahub/datahub-web-react/src/graphql/dataset.graphql
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(140)get_enter_leave_for_kind()
-> enter_fn = getattr(self, f"enter_{kind}", None)
(Pdb) print(kind)
boolean_value
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(141)get_enter_leave_for_kind()
-> if not enter_fn:
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(142)get_enter_leave_for_kind()
-> enter_fn = getattr(self, "enter", None)
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(143)get_enter_leave_for_kind()
-> leave_fn = getattr(self, f"leave_{kind}", None)
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(144)get_enter_leave_for_kind()
-> if not leave_fn:
(Pdb) leave_fn
<bound method GraphQLToPython.leave_boolean_value of <sgqlc.codegen.operation.GraphQLToPython object at 0x7eff0170abd0>>
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(146)get_enter_leave_for_kind()
-> enter_leave = EnterLeaveVisitor(enter_fn, leave_fn)
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(147)get_enter_leave_for_kind()
-> self.enter_leave_map[kind] = enter_leave
(Pdb) enter_leave
EnterLeaveVisitor(enter=None, leave=<bound method GraphQLToPython.leave_boolean_value of <sgqlc.codegen.operation.GraphQLToPython object at 0x7eff0170abd0>>)
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(148)get_enter_leave_for_kind()
-> return enter_leave
(Pdb) self.enter_leave_map[kind]
EnterLeaveVisitor(enter=None, leave=<bound method GraphQLToPython.leave_boolean_value of <sgqlc.codegen.operation.GraphQLToPython object at 0x7eff0170abd0>>)
(Pdb) n
--Return--
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(148)get_enter_leave_for_kind()->EnterLeaveVis...eff0170abd0>>)
-> return enter_leave
(Pdb) list
143                 leave_fn = getattr(self, f"leave_{kind}", None)
144                 if not leave_fn:
145                     leave_fn = getattr(self, "leave", None)
146                 enter_leave = EnterLeaveVisitor(enter_fn, leave_fn)
147                 self.enter_leave_map[kind] = enter_leave
148  ->             return enter_leave
149  
150         def get_visit_fn(
151             self, kind: str, is_leaving: bool = False
152         ) -> Optional[Callable[..., Optional[VisitorAction]]]:
153             """Get the visit function for the given node kind and direction.
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(261)visit()
-> visit_fn = enter_leave.leave if is_leaving else enter_leave.enter
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(262)visit()
-> if visit_fn:
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(282)visit()
-> result = None
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(284)visit()
-> if result is None and is_edited:
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(287)visit()
-> if is_leaving:
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(291)visit()
-> stack = Stack(in_array, idx, keys, edits, stack)
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(292)visit()
-> in_array = isinstance(node, tuple)
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(293)visit()
-> keys = node if in_array else visitor_keys.get(node.kind, ())
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(294)visit()
-> idx = -1
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(295)visit()
-> edits = []
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(296)visit()
-> if parent:
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(297)visit()
-> ancestors_append(parent)
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(298)visit()
-> parent = node
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(300)visit()
-> if not stack:
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(216)visit()
-> idx += 1
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(217)visit()
-> is_leaving = idx == len(keys)
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(218)visit()
-> is_edited = is_leaving and edits
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(219)visit()
-> if is_leaving:
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(220)visit()
-> key = path[-1] if ancestors else None
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(221)visit()
-> node = parent
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(222)visit()
-> parent = ancestors_pop() if ancestors else None
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(223)visit()
-> if is_edited:
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(239)visit()
-> idx = stack.idx
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(240)visit()
-> keys = stack.keys
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(241)visit()
-> edits = stack.edits
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(242)visit()
-> in_array = stack.in_array
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(243)visit()
-> stack = stack.prev
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(255)visit()
-> if isinstance(node, tuple):
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(258)visit()
-> if not isinstance(node, Node):
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(260)visit()
-> enter_leave = visitor.get_enter_leave_for_kind(node.kind)
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(261)visit()
-> visit_fn = enter_leave.leave if is_leaving else enter_leave.enter
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(262)visit()
-> if visit_fn:
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(263)visit()
-> result = visit_fn(node, key, parent, path, ancestors)
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(265)visit()
-> if result is BREAK or result is True:
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(266)visit()
-> break
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(303)visit()
-> if edits:
(Pdb) n
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(304)visit()
-> return edits[-1][1]
(Pdb) n
--Return--
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/graphql/language/visitor.py(304)visit()->'autoRenderOnly'
-> return edits[-1][1]
(Pdb) n
ValueError: not enough values to unpack (expected 3, got 1)
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/sgqlc/codegen/operation.py(857)write_operation()
-> for kind, name, code in visit(gql, visitor):
(Pdb) n
--Return--
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/sgqlc/codegen/operation.py(857)write_operation()->None
-> for kind, name, code in visit(gql, visitor):
(Pdb) n
ValueError: not enough values to unpack (expected 3, got 1)
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/sgqlc/codegen/operation.py(846)write_operations()
-> self.write_operation(source)
(Pdb) n
--Return--
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/sgqlc/codegen/operation.py(846)write_operations()->None
-> self.write_operation(source)
(Pdb) n
ValueError: not enough values to unpack (expected 3, got 1)
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/sgqlc/codegen/operation.py(826)write()
-> self.write_operations()
(Pdb) n
--Return--
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/sgqlc/codegen/operation.py(826)write()->None
-> self.write_operations()
(Pdb) n
ValueError: not enough values to unpack (expected 3, got 1)
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/sgqlc/codegen/operation.py(950)handle_command()
-> gen.write()
(Pdb) n
--Return--
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/sgqlc/codegen/operation.py(950)handle_command()->None
-> gen.write()
(Pdb) n
ValueError: not enough values to unpack (expected 3, got 1)
> /home/georvic/anaconda3/envs/datahub/lib/python3.7/site-packages/sgqlc/codegen/__init__.py(130)main()

It seems that the visit function returns at: https://github.com/graphql-python/graphql-core/blob/0c93b8452eed38d4f800c7e71cf6f3f3758cd1c6/src/graphql/language/visitor.py#L298

edits looks like ``[('name', 'autoRenderOnly')] and edits[-1][1] is returned

J0hnG4lt avatar Jun 20 '23 22:06 J0hnG4lt

hum, the damn bug should be here in the graphql-core (from your backtrace above):

                if result is BREAK or result is True:
                    break

                if result is SKIP or result is False:
                    if not is_leaving:
                        path_pop()
                        continue

as we process a boolean replacing it with True or False, we enter these blocks. I'll see how to solve this, likely as I had to do with None:

# Use Null instead of None as Visitor.leave_* understands None as IDLE,
# which keeps the original node.
class Null:
    def __repr__(self):
        return 'None'

barbieri avatar Jun 21 '23 13:06 barbieri