diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 139c6f683..5d5ae2724 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -20,7 +20,7 @@ jobs: pip install wheel python setup.py sdist bdist_wheel - name: Publish a Python distribution to PyPI - uses: pypa/gh-action-pypi-publish@v1.8.6 + uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.pypi_password }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2c5b7550c..dfc5194ae 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,13 +8,15 @@ jobs: strategy: max-parallel: 4 matrix: - django: ["3.2", "4.0", "4.1"] + django: ["3.2", "4.1", "4.2"] python-version: ["3.8", "3.9", "3.10"] include: - django: "3.2" python-version: "3.7" - django: "4.1" python-version: "3.11" + - django: "4.2" + python-version: "3.11" steps: - uses: actions/checkout@v3 - name: Set up Python ${{ matrix.python-version }} diff --git a/.gitignore b/.gitignore index ff6bd968c..5cfaf0064 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ __pycache__/ # Distribution / packaging .Python env/ +venv/ +.venv/ build/ develop-eggs/ dist/ diff --git a/examples/cookbook-plain/README.md b/examples/cookbook-plain/README.md index dcd242087..b120b7895 100644 --- a/examples/cookbook-plain/README.md +++ b/examples/cookbook-plain/README.md @@ -62,3 +62,12 @@ Now head on over to and run some queries! (See the [Graphene-Django Tutorial](http://docs.graphene-python.org/projects/django/en/latest/tutorial-plain/#testing-our-graphql-schema) for some example queries) + +Testing local graphene-django changes +------------------------------------- + +In `requirements.txt`, replace the entire `graphene-django=...` line with the following (so that we install the local version instead of the one from PyPI): + +``` +../../ # graphene-django +``` diff --git a/examples/cookbook-plain/cookbook/settings.py b/examples/cookbook-plain/cookbook/settings.py index 7eb9d5690..f07f6f6d4 100644 --- a/examples/cookbook-plain/cookbook/settings.py +++ b/examples/cookbook-plain/cookbook/settings.py @@ -5,10 +5,10 @@ Generated by 'django-admin startproject' using Django 1.9. For more information on this file, see -https://docs.djangoproject.com/en/1.9/topics/settings/ +https://docs.djangoproject.com/en/3.2/topics/settings/ For the full list of settings and their values, see -https://docs.djangoproject.com/en/1.9/ref/settings/ +https://docs.djangoproject.com/en/3.2/ref/settings/ """ import os @@ -18,7 +18,7 @@ # Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ +# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = "_$=$%eqxk$8ss4n7mtgarw^5$8^d5+c83!vwatr@i_81myb=e4" @@ -81,7 +81,7 @@ # Database -# https://docs.djangoproject.com/en/1.9/ref/settings/#databases +# https://docs.djangoproject.com/en/3.2/ref/settings/#databases DATABASES = { "default": { @@ -90,9 +90,11 @@ } } +# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" # Password validation -# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators +# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators AUTH_PASSWORD_VALIDATORS = [ { @@ -105,7 +107,7 @@ # Internationalization -# https://docs.djangoproject.com/en/1.9/topics/i18n/ +# https://docs.djangoproject.com/en/3.2/topics/i18n/ LANGUAGE_CODE = "en-us" @@ -119,6 +121,6 @@ # Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/1.9/howto/static-files/ +# https://docs.djangoproject.com/en/3.2/howto/static-files/ STATIC_URL = "/static/" diff --git a/examples/cookbook-plain/requirements.txt b/examples/cookbook-plain/requirements.txt index 85a896390..6e02745de 100644 --- a/examples/cookbook-plain/requirements.txt +++ b/examples/cookbook-plain/requirements.txt @@ -1,4 +1,3 @@ -graphene>=2.1,<3 -graphene-django>=2.1,<3 -graphql-core>=2.1,<3 -django==3.1.14 +django~=3.2 +graphene +graphene-django>=3.1 diff --git a/graphene_django/__init__.py b/graphene_django/__init__.py index d4ef76dd7..dab70cec2 100644 --- a/graphene_django/__init__.py +++ b/graphene_django/__init__.py @@ -1,7 +1,7 @@ from .fields import DjangoConnectionField, DjangoListField from .types import DjangoObjectType -__version__ = "3.1.1" +__version__ = "3.1.2" __all__ = [ "__version__", diff --git a/graphene_django/compat.py b/graphene_django/compat.py index b0e475357..2fcecf6f7 100644 --- a/graphene_django/compat.py +++ b/graphene_django/compat.py @@ -10,16 +10,7 @@ def __init__(self, *args, **kwargs): IntegerRangeField, ArrayField, HStoreField, - JSONField as PGJSONField, RangeField, ) except ImportError: - IntegerRangeField, ArrayField, HStoreField, PGJSONField, RangeField = ( - MissingType, - ) * 5 - -try: - # JSONField is only available from Django 3.1 - from django.db.models import JSONField -except ImportError: - JSONField = MissingType + IntegerRangeField, ArrayField, HStoreField, RangeField = (MissingType,) * 4 diff --git a/graphene_django/converter.py b/graphene_django/converter.py index 375d68312..a43cff76a 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -35,7 +35,7 @@ from graphql import assert_valid_name as assert_name from graphql.pyutils import register_description -from .compat import ArrayField, HStoreField, JSONField, PGJSONField, RangeField +from .compat import ArrayField, HStoreField, RangeField from .fields import DjangoListField, DjangoConnectionField from .settings import graphene_settings from .utils.str_converters import to_const @@ -346,9 +346,8 @@ def convert_postgres_array_to_list(field, registry=None): @convert_django_field.register(HStoreField) -@convert_django_field.register(PGJSONField) -@convert_django_field.register(JSONField) -def convert_pg_and_json_field_to_string(field, registry=None): +@convert_django_field.register(models.JSONField) +def convert_json_field_to_string(field, registry=None): return JSONString( description=get_django_field_description(field), required=not field.null ) diff --git a/graphene_django/rest_framework/mutation.py b/graphene_django/rest_framework/mutation.py index 4062a4423..b7393dad0 100644 --- a/graphene_django/rest_framework/mutation.py +++ b/graphene_django/rest_framework/mutation.py @@ -39,6 +39,9 @@ def fields_for_serializer( field.read_only and is_input and lookup_field != name, # don't show read_only fields in Input + isinstance( + field, serializers.HiddenField + ), # don't show hidden fields in Input ] ) diff --git a/graphene_django/rest_framework/tests/test_mutation.py b/graphene_django/rest_framework/tests/test_mutation.py index 5de823773..91d99f02c 100644 --- a/graphene_django/rest_framework/tests/test_mutation.py +++ b/graphene_django/rest_framework/tests/test_mutation.py @@ -164,6 +164,21 @@ class Meta: ), "'cool_name' is read_only field and shouldn't be on arguments" +def test_hidden_fields(): + class SerializerWithHiddenField(serializers.Serializer): + cool_name = serializers.CharField() + user = serializers.HiddenField(default=serializers.CurrentUserDefault()) + + class MyMutation(SerializerMutation): + class Meta: + serializer_class = SerializerWithHiddenField + + assert "cool_name" in MyMutation.Input._meta.fields + assert ( + "user" not in MyMutation.Input._meta.fields + ), "'user' is hidden field and shouldn't be on arguments" + + def test_nested_model(): class MyFakeModelGrapheneType(DjangoObjectType): class Meta: diff --git a/graphene_django/templates/graphene/graphiql.html b/graphene_django/templates/graphene/graphiql.html index ddff8fc8e..52421e868 100644 --- a/graphene_django/templates/graphene/graphiql.html +++ b/graphene_django/templates/graphene/graphiql.html @@ -21,6 +21,10 @@ integrity="{{graphiql_css_sri}}" rel="stylesheet" crossorigin="anonymous" /> + diff --git a/graphene_django/tests/test_command.py b/graphene_django/tests/test_command.py index a281abbd2..f7325d569 100644 --- a/graphene_django/tests/test_command.py +++ b/graphene_django/tests/test_command.py @@ -46,7 +46,7 @@ class Query(ObjectType): open_mock.assert_called_once() handle = open_mock() - assert handle.write.called_once() + handle.write.assert_called_once() schema_output = handle.write.call_args[0][0] assert schema_output == dedent( diff --git a/graphene_django/tests/test_converter.py b/graphene_django/tests/test_converter.py index 4996505a9..7f4e350ca 100644 --- a/graphene_django/tests/test_converter.py +++ b/graphene_django/tests/test_converter.py @@ -15,8 +15,6 @@ from ..compat import ( ArrayField, HStoreField, - JSONField, - PGJSONField, MissingType, RangeField, ) @@ -372,16 +370,6 @@ def test_should_postgres_hstore_convert_string(): assert_conversion(HStoreField, JSONString) -@pytest.mark.skipif(PGJSONField is MissingType, reason="PGJSONField should exist") -def test_should_postgres_json_convert_string(): - assert_conversion(PGJSONField, JSONString) - - -@pytest.mark.skipif(JSONField is MissingType, reason="JSONField should exist") -def test_should_json_convert_string(): - assert_conversion(JSONField, JSONString) - - @pytest.mark.skipif(RangeField is MissingType, reason="RangeField should exist") def test_should_postgres_range_convert_list(): from django.contrib.postgres.fields import IntegerRangeField diff --git a/graphene_django/tests/test_query.py b/graphene_django/tests/test_query.py index 383ff2e33..68bdc7d94 100644 --- a/graphene_django/tests/test_query.py +++ b/graphene_django/tests/test_query.py @@ -119,13 +119,12 @@ def test_should_query_postgres_fields(): from django.contrib.postgres.fields import ( IntegerRangeField, ArrayField, - JSONField, HStoreField, ) class Event(models.Model): ages = IntegerRangeField(help_text="The age ranges") - data = JSONField(help_text="Data") + data = models.JSONField(help_text="Data") store = HStoreField() tags = ArrayField(models.CharField(max_length=50)) diff --git a/graphene_django/views.py b/graphene_django/views.py index 377b75d99..3fb87d410 100644 --- a/graphene_django/views.py +++ b/graphene_django/views.py @@ -66,18 +66,21 @@ class GraphQLView(View): react_dom_sri = "sha256-nbMykgB6tsOFJ7OdVmPpdqMFVk4ZsqWocT6issAPUF0=" # The GraphiQL React app. - graphiql_version = "2.4.1" # "1.0.3" - graphiql_sri = "sha256-s+f7CFAPSUIygFnRC2nfoiEKd3liCUy+snSdYFAoLUc=" # "sha256-VR4buIDY9ZXSyCNFHFNik6uSe0MhigCzgN4u7moCOTk=" - graphiql_css_sri = "sha256-88yn8FJMyGboGs4Bj+Pbb3kWOWXo7jmb+XCRHE+282k=" # "sha256-LwqxjyZgqXDYbpxQJ5zLQeNcf7WVNSJ+r8yp2rnWE/E=" + graphiql_version = "2.4.7" + graphiql_sri = "sha256-n/LKaELupC1H/PU6joz+ybeRJHT2xCdekEt6OYMOOZU=" + graphiql_css_sri = "sha256-OsbM+LQHcnFHi0iH7AUKueZvDcEBoy/z4hJ7jx1cpsM=" # The websocket transport library for subscriptions. - subscriptions_transport_ws_version = "5.12.1" + subscriptions_transport_ws_version = "5.13.1" subscriptions_transport_ws_sri = ( "sha256-EZhvg6ANJrBsgLvLAa0uuHNLepLJVCFYS+xlb5U/bqw=" ) graphiql_plugin_explorer_version = "0.1.15" graphiql_plugin_explorer_sri = "sha256-3hUuhBXdXlfCj6RTeEkJFtEh/kUG+TCDASFpFPLrzvE=" + graphiql_plugin_explorer_css_sri = ( + "sha256-fA0LPUlukMNR6L4SPSeFqDTYav8QdWjQ2nr559Zln1U=" + ) schema = None graphiql = False diff --git a/setup.py b/setup.py index abf605991..87842bb5e 100644 --- a/setup.py +++ b/setup.py @@ -38,7 +38,7 @@ version=version, description="Graphene Django integration", long_description=open("README.md").read(), - long_description_content_type='text/markdown', + long_description_content_type="text/markdown", url="https://github.com/graphql-python/graphene-django", author="Syrus Akbary", author_email="me@syrusakbary.com", @@ -56,8 +56,8 @@ "Programming Language :: Python :: Implementation :: PyPy", "Framework :: Django", "Framework :: Django :: 3.2", - "Framework :: Django :: 4.0", "Framework :: Django :: 4.1", + "Framework :: Django :: 4.2", ], keywords="api graphql protocol rest relay graphene", packages=find_packages(exclude=["tests", "examples", "examples.*"]), diff --git a/tox.ini b/tox.ini index e186f30ef..9739b1c16 100644 --- a/tox.ini +++ b/tox.ini @@ -1,8 +1,8 @@ [tox] envlist = py{37,38,39,310}-django32, - py{38,39,310}-django{40,41,main}, - py311-django{41,main} + py{38,39,310}-django{41,42,main}, + py311-django{41,42,main} pre-commit [gh-actions] @@ -16,8 +16,8 @@ python = [gh-actions:env] DJANGO = 3.2: django32 - 4.0: django40 4.1: django41 + 4.2: django42 main: djangomain [testenv] @@ -30,8 +30,8 @@ deps = -e.[test] psycopg2-binary django32: Django>=3.2,<4.0 - django40: Django>=4.0,<4.1 django41: Django>=4.1,<4.2 + django42: Django>=4.2,<4.3 djangomain: https://github.com/django/django/archive/main.zip commands = {posargs:py.test --cov=graphene_django graphene_django examples}