Allow graphql schema export to use a canonical representation (#439)

When we use the `graphql_schema` management command, the output can vary from run to run depending on arbitrary factors (because there is no guarantee made about the order used to output JSON dictionary keys). This makes it difficult to compare two schema's at different points in time.

We address this by including a new `canonical` flag to the command, which uses standard `json.dump` funcitonality to sort dictionary keys and force pretty-printed output.
This commit is contained in:
Gary Donovan 2019-03-31 21:30:29 +11:00 committed by Jonathan Kim
parent 1ad0347479
commit fcc3de2a90
4 changed files with 20 additions and 5 deletions

View File

@ -11,7 +11,7 @@ data to ``schema.json`` that is compatible with babel-relay-plugin.
Usage
-----
Include ``graphene_django`` to ``INSTALLED_APPS`` in you project
Include ``graphene_django`` to ``INSTALLED_APPS`` in your project
settings:
.. code:: python
@ -29,6 +29,8 @@ It dumps your full introspection schema to ``schema.json`` inside your
project root directory. Point ``babel-relay-plugin`` to this file and
you're ready to use Relay with Graphene GraphQL implementation.
The schema file is sorted to create a reproducible canonical representation.
Advanced Usage
--------------

View File

@ -39,7 +39,7 @@ class Command(CommandArguments):
def save_file(self, out, schema_dict, indent):
with open(out, "w") as outfile:
json.dump(schema_dict, outfile, indent=indent)
json.dump(schema_dict, outfile, indent=indent, sort_keys=True)
def handle(self, *args, **options):
options_schema = options.get("schema")
@ -65,7 +65,7 @@ class Command(CommandArguments):
indent = options.get("indent")
schema_dict = {"data": schema.introspect()}
if out == '-':
self.stdout.write(json.dumps(schema_dict, indent=indent))
self.stdout.write(json.dumps(schema_dict, indent=indent, sort_keys=True))
else:
self.save_file(out, schema_dict, indent)

View File

@ -28,7 +28,7 @@ except ImportError:
DEFAULTS = {
"SCHEMA": None,
"SCHEMA_OUTPUT": "schema.json",
"SCHEMA_INDENT": None,
"SCHEMA_INDENT": 2,
"MIDDLEWARE": (),
# Set to True if the connection fields must have
# either the first or last argument

View File

@ -1,5 +1,5 @@
from django.core import management
from mock import patch
from mock import patch, mock_open
from six import StringIO
@ -8,3 +8,16 @@ def test_generate_file_on_call_graphql_schema(savefile_mock, settings):
out = StringIO()
management.call_command("graphql_schema", schema="", stdout=out)
assert "Successfully dumped GraphQL schema to schema.json" in out.getvalue()
@patch('json.dump')
def test_files_are_canonical(dump_mock):
open_mock = mock_open()
with patch('graphene_django.management.commands.graphql_schema.open', open_mock):
management.call_command('graphql_schema', schema='')
open_mock.assert_called_once()
dump_mock.assert_called_once()
assert dump_mock.call_args[1]["sort_keys"], "json.mock() should be used to sort the output"
assert dump_mock.call_args[1]["indent"] > 0, "output should be pretty-printed by default"