File: test_description.py

package info (click to toggle)
graphql-core 3.2.6-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,384 kB
  • sloc: python: 45,812; makefile: 26; sh: 13
file content (269 lines) | stat: -rw-r--r-- 10,731 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
from contextlib import contextmanager
from typing import cast

from graphql import graphql_sync
from graphql.pyutils import (
    Description,
    is_description,
    register_description,
    unregister_description,
)
from graphql.type import (
    GraphQLArgument,
    GraphQLDirective,
    GraphQLEnumValue,
    GraphQLField,
    GraphQLInputField,
    GraphQLNamedType,
    GraphQLObjectType,
    GraphQLSchema,
    GraphQLString,
)
from graphql.utilities import get_introspection_query, print_schema
from pytest import raises

from ..utils import dedent


class LazyString:
    def __init__(self, text: object) -> None:
        self.text = text

    def __str__(self) -> str:
        return str(self.text)


lazy_string = cast(str, LazyString("Why am I so lazy?"))


@contextmanager
def registered(base: type):
    register_description(base)
    try:
        yield None
    finally:
        unregister_description(base)


def describe_description():
    def by_default_strings_are_accepted():
        is_description("")
        is_description("text")

    def by_default_non_strings_are_not_accepted():
        assert not is_description(None)
        assert not is_description(b"bytes")
        assert not is_description(0)
        assert not is_description(42)
        assert not is_description(("tuple",))
        assert not is_description(["list"])

    def after_registration_lazy_strings_are_accepted():
        with registered(LazyString):
            assert is_description("not lazy")
            assert is_description(lazy_string)
            assert not is_description(42)

    def can_register_and_unregister():
        try:
            assert Description.bases is str
            register_description(str)
            assert Description.bases is str
            register_description(int)
            assert Description.bases == (str, int)
            register_description(int)
            assert Description.bases == (str, int)
            register_description(float)
            assert Description.bases == (str, int, float)
            unregister_description(int)
            assert Description.bases == (str, float)
            unregister_description(float)
            assert Description.bases is str
            unregister_description(str)
            assert Description.bases is object
            register_description(str)
            assert Description.bases is str
            register_description(object)
            assert Description.bases is object
            Description.bases = (str,)
            unregister_description(str)
            assert Description.bases is object
            unregister_description(str)
            assert Description.bases is object
        finally:
            Description.bases = str

    def can_only_register_types():
        with raises(TypeError, match="Only types can be registered\\."):
            # noinspection PyTypeChecker
            register_description("foo")  # type: ignore

    def can_only_unregister_types():
        with raises(TypeError, match="Only types can be unregistered\\."):
            # noinspection PyTypeChecker
            unregister_description("foo")  # type: ignore

    def describe_graphql_types():
        def graphql_named_type():
            named_type = GraphQLNamedType(name="Foo", description="not lazy")
            assert named_type.name == "Foo"
            assert named_type.description == "not lazy"
            with raises(TypeError, match="Expected name to be a string\\."):
                GraphQLNamedType(name=lazy_string)
            with raises(TypeError, match="The description must be a string\\."):
                GraphQLNamedType(name="Foo", description=lazy_string)
            with registered(LazyString):
                named_type = GraphQLNamedType(name="Foo", description=lazy_string)
                assert named_type.description is lazy_string
                assert str(named_type.description).endswith("lazy?")
                with raises(TypeError, match="Expected name to be a string\\."):
                    GraphQLNamedType(name=lazy_string)

        def graphql_field():
            field = GraphQLField(GraphQLString, description="not lazy")
            assert field.description == "not lazy"
            field = GraphQLField(GraphQLString, deprecation_reason="not lazy")
            assert field.deprecation_reason == "not lazy"
            with raises(TypeError, match="The description must be a string\\."):
                GraphQLField(GraphQLString, description=lazy_string)
            with raises(TypeError, match="The deprecation reason must be a string\\."):
                GraphQLField(GraphQLString, deprecation_reason=lazy_string)
            with registered(LazyString):
                field = GraphQLField(
                    GraphQLString,
                    description=lazy_string,
                    deprecation_reason=lazy_string,
                )
                assert field.description is lazy_string
                assert str(field.description).endswith("lazy?")
                assert field.deprecation_reason is lazy_string
                assert str(field.deprecation_reason).endswith("lazy?")

        def graphql_argument():
            arg = GraphQLArgument(GraphQLString, description="not lazy")
            assert arg.description == "not lazy"
            with raises(TypeError, match="Argument description must be a string\\."):
                GraphQLArgument(GraphQLString, description=lazy_string)
            with registered(LazyString):
                arg = GraphQLArgument(GraphQLString, description=lazy_string)
                assert arg.description is lazy_string
                assert str(arg.description).endswith("lazy?")

        def graphql_enum_value():
            value = GraphQLEnumValue(description="not lazy")
            assert value.description == "not lazy"
            value = GraphQLEnumValue(deprecation_reason="not lazy")
            assert value.deprecation_reason == "not lazy"
            with raises(
                TypeError, match="The description of the enum value must be a string\\."
            ):
                GraphQLEnumValue(description=lazy_string)
            with raises(
                TypeError,
                match="The deprecation reason for the enum value must be a string\\.",
            ):
                GraphQLEnumValue(deprecation_reason=lazy_string)
            with registered(LazyString):
                value = GraphQLEnumValue(
                    description=lazy_string, deprecation_reason=lazy_string
                )
                assert value.description is lazy_string
                assert str(value.description).endswith("lazy?")
                assert value.deprecation_reason is lazy_string
                assert str(value.deprecation_reason).endswith("lazy?")

        def graphql_input_field():
            field = GraphQLInputField(GraphQLString, description="not lazy")
            assert field.description == "not lazy"
            with raises(TypeError, match="Input field description must be a string\\."):
                GraphQLInputField(GraphQLString, description=lazy_string)
            with registered(LazyString):
                field = GraphQLInputField(GraphQLString, description=lazy_string)
                assert field.description is lazy_string
                assert str(field.description).endswith("lazy?")

        def graphql_directive():
            directive = GraphQLDirective("Foo", [], description="not lazy")
            assert directive.name == "Foo"
            assert directive.description == "not lazy"
            with raises(TypeError, match="Expected name to be a string\\."):
                GraphQLDirective(lazy_string, [])
            with raises(TypeError, match="Foo description must be a string\\."):
                GraphQLDirective("Foo", [], description=lazy_string)
            with registered(LazyString):
                directive = GraphQLDirective("Foo", [], description=lazy_string)
                assert directive.description is lazy_string
                assert str(directive.description).endswith("lazy?")
                with raises(TypeError, match="Expected name to be a string\\."):
                    GraphQLDirective(lazy_string, [])

    def handels_introspection():
        class Lazy:
            def __init__(self, text: str):
                self.text = text
                self.evaluated = False

            def __str__(self) -> str:
                self.evaluated = True
                return self.text

        description = Lazy("a lazy description")
        deprecation_reason = Lazy("a lazy reason")

        with registered(Lazy):
            field = GraphQLField(
                GraphQLString,
                description=cast(str, description),
                deprecation_reason=cast(str, deprecation_reason),
            )

        schema = GraphQLSchema(GraphQLObjectType("Query", {"lazyField": field}))

        query = get_introspection_query(descriptions=True)
        assert not description.evaluated
        assert not deprecation_reason.evaluated
        result = graphql_sync(schema, query)
        assert description.evaluated
        assert deprecation_reason.evaluated
        assert result.data
        introspected_query = result.data["__schema"]["types"][0]
        assert introspected_query["name"] == "Query"
        introspected_field = introspected_query["fields"][0]
        assert introspected_field["name"] == "lazyField"
        assert introspected_field["description"] == "a lazy description"
        assert introspected_field["deprecationReason"] == "a lazy reason"

    def handles_printing():
        class Lazy:
            def __init__(self, text: str):
                self.text = text
                self.evaluated = False

            def __str__(self) -> str:
                self.evaluated = True
                return self.text

        description = Lazy("a lazy description")
        deprecation_reason = Lazy("a lazy reason")

        with registered(Lazy):
            field = GraphQLField(
                GraphQLString,
                description=cast(str, description),
                deprecation_reason=cast(str, deprecation_reason),
            )

        schema = GraphQLSchema(GraphQLObjectType("Query", {"lazyField": field}))

        assert not description.evaluated
        assert not deprecation_reason.evaluated
        assert print_schema(schema) == dedent(
            '''
            type Query {
              """a lazy description"""
              lazyField: String @deprecated(reason: "a lazy reason")
            }
            '''
        )
        assert description.evaluated
        assert deprecation_reason.evaluated