Repository: strawberry-graphql/strawberry
Pull request #101 (2019-07-08 05:45:13)

Bump pytest from 5.0.0 to 5.0.1
Bumps [pytest](https://github.com/pytest-dev/pytest) from 5.0.0 to 5.0.1.
<details>
<summary>Changelog</summary>

*Sourced from [pytest's changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst).*

> pytest 5.0.1 (2019-07-04)
> =========================
> 
> Bug Fixes
> ---------
> 
> -   [\#5479](https://github-redirect.dependabot.com/pytest-dev/pytest/issues/5479): Improve quoting in `raises` match failure message.
> -   [\#5523](https://github-redirect.dependabot.com/pytest-dev/pytest/issues/5523): Fixed using multiple short options together in the command-line (for example `-vs`) in Python 3.8+.
> -   [\#5547](https://github-redirect.dependabot.com/pytest-dev/pytest/issues/5547): `--step-wise` now handles `xfail(strict=True)` markers properly.
> 
> Improved Documentation
> ----------------------
> 
> -   [\#5517](https://github-redirect.dependabot.com/pytest-dev/pytest/issues/5517): Improve "Declaring new hooks" section in chapter "Writing Plugins"
</details>
<details>
<summary>Commits</summary>

- [`bb29f31`](https://github.com/pytest-dev/pytest/commit/bb29f31d2278fc93efba7ef3e123616c13ce8022) Preparing release version 5.0.1
- [`b1928f8`](https://github.com/pytest-dev/pytest/commit/b1928f878d33b912851391c32adb4c0b91fb70c0) Handle xfail(strict=True) properly in --step-wise mode ([#5555](https://github-redirect.dependabot.com/pytest-dev/pytest/issues/5555))
- [`8651d88`](https://github.com/pytest-dev/pytest/commit/8651d880a06c078d8c04ec8c99df1a05bc9826d7) Handle xfail(strict=True) properly in --step-wise mode
- [`95824c5`](https://github.com/pytest-dev/pytest/commit/95824c588a333c54780e6ea82393488b6a6a81d4) Improve quoting in raises match failure message ([#5553](https://github-redirect.dependabot.com/pytest-dev/pytest/issues/5553))
- [`caa08eb`](https://github.com/pytest-dev/pytest/commit/caa08ebd4536bbabfb0e1edd3d438be911cfab51) Improve quoting in raises match failure message
- [`b08ae44`](https://github.com/pytest-dev/pytest/commit/b08ae4449b6ab0e70296cc11fc3f1f0ad0e97255) Add docs about Tidelift and OpenCollective ([#5527](https://github-redirect.dependabot.com/pytest-dev/pytest/issues/5527))
- [`776a632`](https://github.com/pytest-dev/pytest/commit/776a632170d1bb3da0764f5277ec6c9ebb9d3781) Merge pull request [#5540](https://github-redirect.dependabot.com/pytest-dev/pytest/issues/5540) from bazcrown/yml2yaml
- [`d74a975`](https://github.com/pytest-dev/pytest/commit/d74a975f8287e8ee1802aecbb449a47239b3e757) remove documentation about setuptools integration Refs [#5534](https://github-redirect.dependabot.com/pytest-dev/pytest/issues/5534) Fi… ([#5546](https://github-redirect.dependabot.com/pytest-dev/pytest/issues/5546))
- [`2b9522e`](https://github.com/pytest-dev/pytest/commit/2b9522e9da15107bf3a96083e0221ad6cce47bb6) remove documentation about setuptools integration Refs [#5534](https://github-redirect.dependabot.com/pytest-dev/pytest/issues/5534)
- [`528ee3e`](https://github.com/pytest-dev/pytest/commit/528ee3e1c5b461c91948632aadd835ede83cc50b) Add upcoming trainings ([#5544](https://github-redirect.dependabot.com/pytest-dev/pytest/issues/5544))
- Additional commits viewable in [compare view](https://github.com/pytest-dev/pytest/compare/5.0.0...5.0.1)
</details>
<br />

[![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=pytest&package-manager=pip&previous-version=5.0.0&new-version=5.0.1)](https://dependabot.com/compatibility-score.html?dependency-name=pytest&package-manager=pip&previous-version=5.0.0&new-version=5.0.1)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot ignore this [patch|minor|major] version` will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it). To ignore the version in this PR you can just close it
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
- `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language
- `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language
- `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language
- `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language
- `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme

Additionally, you can set the following in your Dependabot [dashboard](https://app.dependabot.com):
- Update frequency (including time of day and day of week)
- Pull request limits (per update run and/or open at any time)
- Out-of-range updates (receive only lockfile updates, if desired)
- Security updates (receive only security updates, if desired)

Finally, you can contact us by mentioning @dependabot.

</details>

codecov[bot]: # [Codecov](https://codecov.io/gh/strawberry-graphql/strawberry/pull/101?src=pr&el=h1) Report
> Merging [#101](https://codecov.io/gh/strawberry-graphql/strawberry/pull/101?src=pr&el=desc) into [master](https://codecov.io/gh/strawberry-graphql/strawberry/commit/a98d057a370bcd395934a28baa91a370ea58e053?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `n/a`.


```diff
@@           Coverage Diff           @@
##           master     #101   +/-   ##
=======================================
  Coverage   89.55%   89.55%           
=======================================
  Files          19       19           
  Lines         383      383           
=======================================
  Hits          343      343           
  Misses         40       40
```


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f308e8bd..e77fca59 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,49 @@
 CHANGELOG
 =========
 
+0.13.1 - 2019-07-17
+-------------------
+
+Fix missing fields when extending a class, now we can do this:
+
+
+```python
+@strawberry.type
+class Parent:
+    cheese: str = "swiss"
+
+    @strawberry.field
+    def friend(self, info) -> str:
+        return 'food'
+
+@strawberry.type
+class Schema(Parent):
+    cake: str = "made_in_swiss"
+```
+
+0.13.0 - 2019-07-16
+-------------------
+
+This release adds field support for permissions 
+
+```python
+import strawberry
+
+from strawberry.permission import BasePermission
+
+class IsAdmin(BasePermission):
+    message = "You are not authorized"
+
+    def has_permission(self, info):
+      return False
+
+@strawberry.type
+class Query:
+    @strawberry.field(permisson_classes=[IsAdmin])
+    def hello(self, info) -> str:
+      return "Hello"
+```
+
 0.12.0 - 2019-06-25
 -------------------
 
diff --git a/poetry.lock b/poetry.lock
index b200a16b..59ffc5e6 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -154,8 +154,8 @@ category = "main"
 description = "GraphQL-core-next is a Python port of GraphQL.js, the JavaScript reference implementation for GraphQL."
 name = "graphql-core-next"
 optional = false
-python-versions = ">=3.6"
-version = "1.0.5"
+python-versions = ">=3.6,<4"
+version = "1.1.0"
 
 [[package]]
 category = "dev"
@@ -323,7 +323,7 @@ description = "pytest: simple powerful testing with Python"
 name = "pytest"
 optional = false
 python-versions = ">=3.5"
-version = "5.0.0"
+version = "5.0.1"
 
 [package.dependencies]
 atomicwrites = ">=1.0"
@@ -398,7 +398,7 @@ description = "The little ASGI library that shines."
 name = "starlette"
 optional = false
 python-versions = ">=3.6"
-version = "0.12.1"
+version = "0.12.4"
 
 [[package]]
 category = "dev"
@@ -481,7 +481,7 @@ python-versions = ">=2.7"
 version = "0.5.1"
 
 [metadata]
-content-hash = "546303511132edee281db9719065d5022892271a5696297be2f0795e5fd408b6"
+content-hash = "12b5a553041ff70d3aebc90c71505bca35fe9733eaf4a7b01f64d06ef5adf735"
 python-versions = "^3.7"
 
 [metadata.hashes]
@@ -500,7 +500,7 @@ curtsies = ["89c802ec051d01dec6fc983e9856a3706e4ea8265d2940b1f6d504a9e26ed3a9"]
 entrypoints = ["589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", "c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"]
 fancycompleter = ["d2522f1f3512371f295379c4c0d1962de06762eb586c199620a2a5d423539b12"]
 flake8 = ["859996073f341f2670741b51ec1e67a01da142831aa1fdc6242dbf88dffbe661", "a796a115208f5c03b18f332f7c11729812c8c3ded6c46319c59b53efd3819da8"]
-graphql-core-next = ["5a6cdf23a3b24fa738a903b9fcdaa1db2768a6552f8d1fb8fb79d9add16d090d", "c663ccc36d9a5ece606b5b4f5509835f0ec8d6e6b941992ced67384edcbfd045"]
+graphql-core-next = ["720b2ebbaa1ce5faa0876e2c2b9a36f77c984b5d5731c9963741bb947cd8ab04", "9b6d148280f8f3039bf2ae5e563e941c3d21b783e012209ab8d4cfaa6f206c1b"]
 greenlet = ["000546ad01e6389e98626c1367be58efa613fa82a1be98b0c6fc24b563acc6d0", "0d48200bc50cbf498716712129eef819b1729339e34c3ae71656964dac907c28", "23d12eacffa9d0f290c0fe0c4e81ba6d5f3a5b7ac3c30a5eaf0126bf4deda5c8", "37c9ba82bd82eb6a23c2e5acc03055c0e45697253b2393c9a50cef76a3985304", "51503524dd6f152ab4ad1fbd168fc6c30b5795e8c70be4410a64940b3abb55c0", "8041e2de00e745c0e05a502d6e6db310db7faa7c979b3a5877123548a4c0b214", "81fcd96a275209ef117e9ec91f75c731fa18dcfd9ffaa1c0adbdaa3616a86043", "853da4f9563d982e4121fed8c92eea1a4594a2299037b3034c3c898cb8e933d6", "8b4572c334593d449113f9dc8d19b93b7b271bdbe90ba7509eb178923327b625", "9416443e219356e3c31f1f918a91badf2e37acf297e2fa13d24d1cc2380f8fbc", "9854f612e1b59ec66804931df5add3b2d5ef0067748ea29dc60f0efdcda9a638", "99a26afdb82ea83a265137a398f570402aa1f2b5dfb4ac3300c026931817b163", "a19bf883b3384957e4a4a13e6bd1ae3d85ae87f4beb5957e35b0be287f12f4e4", "a9f145660588187ff835c55a7d2ddf6abfc570c2651c276d3d4be8a2766db490", "ac57fcdcfb0b73bb3203b58a14501abb7e5ff9ea5e2edfa06bb03035f0cff248", "bcb530089ff24f6458a81ac3fa699e8c00194208a724b644ecc68422e1111939", "beeabe25c3b704f7d56b573f7d2ff88fc99f0138e43480cecdfcaa3b87fe4f87", "d634a7ea1fc3380ff96f9e44d8d22f38418c1c381d5fac680b272d7d90883720", "d97b0661e1aead761f0ded3b769044bb00ed5d33e1ec865e891a8b128bf7c656"]
 h11 = ["acca6a44cb52a32ab442b1779adf0875c443c689e9e028f8d831a3769f9c5208", "f2b1ca39bfed357d1f19ac732913d5f9faa54a5062eca7d2ec3a916cfb7ae4c7"]
 httptools = ["e00cbd7ba01ff748e494248183abc6e153f49181169d8a3d41bb49132ca01dfc"]
@@ -519,13 +519,13 @@ pyflakes = ["17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0",
 pygments = ["71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", "881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297"]
 pyparsing = ["1873c03321fc118f4e9746baf201ff990ceb915f433f23b395f5580d1840cb2a", "9b6323ef4ab914af344ba97510e966d64ba91055d6b9afa6b30799340e89cc03"]
 pyrepl = ["292570f34b5502e871bbb966d639474f2b57fbfcd3373c2d6a2f3d56e681a775"]
-pytest = ["2878de8ae1c79a62c012da6186b88ff0562ea96ce29c4208d2a9b11d9f607df1", "95b700cf21ed5b7e91bce7a6b5a573b2e3ef7b3643d00f681d8f9c4672f9fbdf"]
+pytest = ["6ef6d06de77ce2961156013e9dff62f1b2688aa04d0dc244299fe7d67e09370d", "a736fed91c12681a7b34617c8fcefe39ea04599ca72c608751c31d89579a3f77"]
 pytest-asyncio = ["9fac5100fd716cbecf6ef89233e8590a4ad61d729d1732e0a96b84182df1daaf", "d734718e25cfc32d2bf78d346e99d33724deeba774cc4afdf491530c6184b63b"]
 pytest-cov = ["2b097cde81a302e1047331b48cadacf23577e431b61e9c6f49a1170bbe3d3da6", "e00ea4fdde970725482f1f35630d12f074e121a23801aabf2ae154ec6bdd343a"]
 pytest-emoji = ["6e34ed21970fa4b80a56ad11417456bd873eb066c02315fe9df0fafe6d4d4436", "e1bd4790d87649c2d09c272c88bdfc4d37c1cc7c7a46583087d7c510944571e8"]
 requests = ["11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", "9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"]
 six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"]
-starlette = ["d12d22f22f859131f6e772f3a2a7a8c43fb3d27c72e06ecbbdbd48506ff835d4"]
+starlette = ["23f1de058ffcc053e9bddd87f49bb8bcda709ed2787d038819f6d8561e71f8d4"]
 toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"]
 typing = ["38566c558a0a94d6531012c8e917b1b8518a41e418f7f15f00e129cc80162ad3", "53765ec4f83a2b720214727e319607879fec4acde22c4fbb54fa2604e79e44ce", "84698954b4e6719e912ef9a42a2431407fe3755590831699debda6fba92aac55"]
 urllib3 = ["b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1", "dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232"]
diff --git a/pyproject.toml b/pyproject.toml
index 8a2abc7e..efc30859 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,7 +1,7 @@
 [tool.poetry]
 name = "strawberry-graphql"
 packages = [ { include = "strawberry" } ]
-version = "0.12.0"
+version = "0.13.1"
 description = "A library for creating GraphQL APIs"
 authors = ["Patrick Arminio <patrick.arminio@gmail.com>"]
 license = "MIT"
@@ -20,7 +20,7 @@ classifiers = [
 [tool.poetry.dependencies]
 python = "^3.7"
 graphql-core-next = "^1.0"
-starlette = "=0.12.1"
+starlette = "=0.12.4"
 click = "^7.0"
 hupper = "^1.5"
 pygments = "^2.3"
diff --git a/strawberry/__init__.py b/strawberry/__init__.py
index 8cbd4ce5..7220b009 100644
--- a/strawberry/__init__.py
+++ b/strawberry/__init__.py
@@ -7,3 +7,4 @@ from .mutation import mutation, subscription  # noqa
 from .scalars import ID  # noqa
 from .schema import Schema  # noqa
 from .type import input, type, interface  # noqa
+from .permission import BasePermission  # noqa
diff --git a/strawberry/field.py b/strawberry/field.py
index 5b5a01ef..708d0d2d 100644
--- a/strawberry/field.py
+++ b/strawberry/field.py
@@ -40,6 +40,7 @@ class LazyFieldWrapper:
         resolver=None,
         name=None,
         description=None,
+        permission_classes=None
     ):
         self._wrapped_obj = obj
         self.is_subscription = is_subscription
@@ -47,6 +48,7 @@ class LazyFieldWrapper:
         self.field_name = name
         self.field_resolver = resolver
         self.field_description = description
+        self.permission_classes = permission_classes or []
 
         if callable(self._wrapped_obj):
             self._check_has_annotations(self._wrapped_obj)
@@ -85,6 +87,23 @@ class LazyFieldWrapper:
     def __call__(self, *args, **kwargs):
         return self._wrapped_obj(self, *args, **kwargs)
 
+    def _get_permissions(self):
+        """
+        Gets all permissions defined in the permission classes
+        >>> strawberry.field(permission_classes=[IsAuthenticated])
+        """
+        return (permission() for permission in self.permission_classes)
+
+    def _check_permissions(self, info):
+        """
+        Checks if the permission should be accepted and
+        raises an exception if not
+        """
+        for permission in self._get_permissions():
+            if not permission.has_permission(info):
+                message = getattr(permission, "message", None)
+                raise PermissionError(message)
+
     @lazy_property
     def field(self):
         return _get_field(
@@ -93,6 +112,7 @@ class LazyFieldWrapper:
             is_subscription=self.is_subscription,
             name=self.field_name,
             description=self.field_description,
+            check_permission=self._check_permissions,
         )
 
 
@@ -128,12 +148,14 @@ class strawberry_field(dataclasses.Field):
         name=None,
         description=None,
         metadata=None,
+        permission_classes=None
     ):
         self.field_name = name
         self.field_description = description
         self.field_resolver = resolver
         self.is_subscription = is_subscription
         self.is_input = is_input
+        self.field_permission_classes = permission_classes
 
         super().__init__(
             # TODO:
@@ -161,6 +183,7 @@ class strawberry_field(dataclasses.Field):
             resolver=self.field_resolver,
             name=self.field_name,
             description=self.field_description,
+            permission_classes=self.field_permission_classes,
         )
 
 
@@ -198,7 +221,13 @@ def convert_args(args, annotations):
 
 
 def _get_field(
-    wrap, *, is_input=False, is_subscription=False, name=None, description=None
+    wrap,
+    *,
+    is_input=False,
+    is_subscription=False,
+    name=None,
+    description=None,
+    check_permission=None
 ):
     name = wrap.__name__
 
@@ -220,8 +249,9 @@ def _get_field(
     }
 
     def resolver(source, info, **args):
+        if check_permission:
+            check_permission(info)
         args = convert_args(args, arguments_annotations)
-
         return wrap(source, info, **args)
 
     field_params = {}
@@ -232,6 +262,8 @@ def _get_field(
         if is_subscription:
 
             def _resolve(event, info):
+                if check_permission:
+                    check_permission(info)
                 return event
 
             field_params.update({"subscribe": resolver, "resolve": _resolve})
@@ -253,6 +285,7 @@ def field(
     resolver=None,
     is_input=False,
     is_subscription=False,
+    permission_classes=None
 ):
     """Annotates a method or property as a GraphQL field.
 
@@ -275,6 +308,7 @@ def field(
         resolver=resolver,
         is_input=is_input,
         is_subscription=is_subscription,
+        permission_classes=permission_classes,
     )
 
     # when calling this with parens we are going to return a strawberry_field
diff --git a/strawberry/permission.py b/strawberry/permission.py
new file mode 100644
index 00000000..f2143014
--- /dev/null
+++ b/strawberry/permission.py
@@ -0,0 +1,9 @@
+class BasePermission:
+    """
+    Base class for creating permissions
+    """
+
+    def has_permission(self, info):
+        raise NotImplementedError(
+            "Permission classes should override has_permission method"
+        )
diff --git a/strawberry/type.py b/strawberry/type.py
index 7297e040..4d3ef22b 100644
--- a/strawberry/type.py
+++ b/strawberry/type.py
@@ -60,11 +60,16 @@ def _process_type(cls, *, is_input=False, is_interface=False, description=None):
                 resolver, is_input=is_input, description=description
             ).field
 
-        strawberry_fields = {
-            key: value
-            for key, value in cls.__dict__.items()
-            if getattr(value, IS_STRAWBERRY_FIELD, False)
-        }
+        strawberry_fields = {}
+
+        for base in [cls, *cls.__bases__]:
+            strawberry_fields.update(
+                {
+                    key: value
+                    for key, value in base.__dict__.items()
+                    if getattr(value, IS_STRAWBERRY_FIELD, False)
+                }
+            )
 
         for key, value in strawberry_fields.items():
             name = getattr(value, "field_name", None) or to_camel_case(key)


Test patch:
diff --git a/tests/test_permission.py b/tests/test_permission.py
new file mode 100644
index 00000000..99682825
--- /dev/null
+++ b/tests/test_permission.py
@@ -0,0 +1,78 @@
+import typing
+
+import pytest
+
+import strawberry
+from graphql import graphql_sync
+from graphql.language import parse
+from graphql.subscription import subscribe
+from strawberry.permission import BasePermission
+
+
+def test_raises_graphql_error_when_permission_method_is_missing():
+    class IsAuthenticated(BasePermission):
+        pass
+
+    @strawberry.type
+    class Query:
+        @strawberry.field(permission_classes=[IsAuthenticated])
+        def user(self, info) -> str:
+            return "patrick"
+
+    schema = strawberry.Schema(query=Query)
+
+    query = "{ user }"
+
+    result = graphql_sync(schema, query)
+    assert (
+        result.errors[0].message
+        == "Permission classes should override has_permission method"
+    )
+
+
+def test_raises_graphql_error_when_permission_is_denied():
+    class IsAuthenticated(BasePermission):
+        message = "User is not authenticated"
+
+        def has_permission(self, info):
+            return False
+
+    @strawberry.type
+    class Query:
+        @strawberry.field(permission_classes=[IsAuthenticated])
+        def user(self, info) -> str:
+            return "patrick"
+
+    schema = strawberry.Schema(query=Query)
+
+    query = "{ user }"
+
+    result = graphql_sync(schema, query)
+    assert result.errors[0].message == "User is not authenticated"
+
+
+@pytest.mark.asyncio
+async def test_raises_permission_error_for_subscription():
+    class IsAdmin(BasePermission):
+        message = "You are not authorized"
+
+        def has_permission(self, info):
+            return False
+
+    @strawberry.type
+    class Query:
+        name: str = "Andrew"
+
+    @strawberry.type
+    class Subscription:
+        @strawberry.subscription(permission_classes=[IsAdmin])
+        async def user(self, info) -> typing.AsyncGenerator[str, None]:
+            yield "Hello"
+
+    schema = strawberry.Schema(query=Query, subscription=Subscription)
+
+    query = "subscription { user }"
+
+    result = await subscribe(schema, parse(query))
+
+    assert result.errors[0].message == "You are not authorized"
diff --git a/tests/test_schema.py b/tests/test_schema.py
index fa41b9bf..00b1a9d3 100644
--- a/tests/test_schema.py
+++ b/tests/test_schema.py
@@ -403,3 +403,34 @@ def test_enum_description():
     ]
 
     assert result.data["pizzas"]["description"] == "We also love pizza"
+
+
+def test_parent_class_fields_are_inherited():
+    @strawberry.type
+    class Parent:
+        cheese: str = "swiss"
+
+        @strawberry.field
+        def friend(self, info) -> str:
+            return "food"
+
+    @strawberry.type
+    class Schema(Parent):
+        cake: str = "made_in_switzerland"
+
+        @strawberry.field
+        def hello_this_is(self, info) -> str:
+            return "patrick"
+
+    schema = strawberry.Schema(query=Schema)
+
+    query = "{ cheese, cake, friend, helloThisIs }"
+
+    result = graphql_sync(schema, query)
+
+    assert not result.errors
+
+    assert result.data["cheese"] == "swiss"
+    assert result.data["cake"] == "made_in_switzerland"
+    assert result.data["friend"] == "food"
+    assert result.data["helloThisIs"] == "patrick"