graphql-python / graphql-core-legacy

GraphQL base implementation for Python (legacy version – see graphql-core for the current one)
MIT License
374 stars 184 forks source link

`print_schema` should be deterministic #135

Open ajhyndman opened 7 years ago

ajhyndman commented 7 years ago

In our project, we commit a graphql schema to our repo. This is useful for running demos, tests and mocking data.

However, now we also want to be able to ensure that the schema is kept up-to-date with a CI check. Unfortunately, printing the schema twice, seems to not be guaranteed to print values in the same order (especially keys in object types, and field arguments). This makes consistency checks significantly harder.

It'd be great if there was a guarantee of determinism. Running the printer repeatedly, against a given schema always outputs the same file.

syrusakbary commented 7 years ago

Hi @ajhyndman, if the type fields are created directly "by hand" (not using any framework like graphene), the order of the fields depend on the dict that you are using to hold the field names and values.

So, if you are using {} instead of OrderedDict, then the dict will be un-ordered and un-deterministic depending on which python env you run the operation in (unless you are in Python 3.6 which preserves the order of the elements in normal dicts {}).

Because of this fact, the schema will print one values or others. If you want to fix this issue, then you would need to switch from {} to OrderedDict in your type resolvers (same in resolver arguments), or using a framework like Graphene that ensures this order.

Let me know if that fixes the issue (please reopen if not).

ajhyndman commented 7 years ago

Thanks for the quick response, @syrusakbary. I'm beginning to suspect that the source of the non-determinism I'm seeing is graphene_django.

We don't have any hand-coded types, but we are using DjangoObjectTypes in our codebase. (DjangoObjectTypes have proven problematic on a few fronts, so we've been backtracking and working toward removing them.)

We'll investigate a little further, and see what we find.

yen223 commented 7 years ago

One potential source of non-deterministic ordering is in graphene's Mutation arguments.

https://github.com/graphql-python/graphene/blob/master/graphene/types/mutation.py#L22: field_args is a dict, not an OrderedDict.

syrusakbary commented 7 years ago

Good feedback! I would love to backtrack and see what is the source of this "non-determinism".

If you can create a repo that helps to reproduce the issue it will be super useful for debugging and fixing the issue (either in graphene or graphene-django).

ajhyndman commented 7 years ago

@syrusakbary

I believe we've managed to isolate the two sources of non-determinism that we were experiencing.

The first is Mutation arguments. The second occurs when a DjangoObject type has multiple synthesized foreign key relationships.

https://github.com/ajhyndman/graphene-experiments

Update: Note that the non-determinism is visible in python 3.5.2 but not in 3.6.