• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MrThearMan / undine / 23836779608

01 Apr 2026 07:16AM UTC coverage: 95.614% (-0.01%) from 95.627%
23836779608

push

github

matti-lamppu
Bump version to 0.3.5

2717 of 2900 branches covered (93.69%)

Branch coverage included in aggregate %.

39684 of 41446 relevant lines covered (95.75%)

3.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.24
/tests/test_entrypoint/test_basic.py
1
from __future__ import annotations
4✔
2

3
from inspect import cleandoc
4✔
4

5
import pytest
4✔
6
from graphql import (
4✔
7
    DirectiveLocation,
8
    GraphQLArgument,
9
    GraphQLError,
10
    GraphQLInt,
11
    GraphQLNonNull,
12
    GraphQLString,
13
    GraphQLUnionType,
14
)
15

16
from undine import Directive, DirectiveArgument, Entrypoint, RootType
4✔
17
from undine.exceptions import DirectiveLocationError
4✔
18
from undine.resolvers import EntrypointFunctionResolver
4✔
19

20

21
def test_entrypoint__function() -> None:
4✔
22
    class Query(RootType):
4✔
23
        @Entrypoint
4✔
24
        def double(self, number: int) -> int:
4✔
25
            return number * 2
×
26

27
    assert repr(Query.double) == f"<undine.entrypoint.Entrypoint(ref={Query.double.ref})>"
4✔
28

29

30
def test_entrypoint__function__attributes() -> None:
4✔
31
    class Query(RootType):
4✔
32
        @Entrypoint
4✔
33
        def double(self, number: int) -> int:
4✔
34
            """Description."""
35
            return number * 2
×
36

37
    assert callable(Query.double.ref)
4✔
38
    assert Query.double.many is False
4✔
39
    assert Query.double.description == "Description."
4✔
40
    assert Query.double.deprecation_reason is None
4✔
41
    assert Query.double.complexity == 0
4✔
42
    assert Query.double.errors == []
4✔
43
    assert Query.double.extensions == {"undine_entrypoint": Query.double}
4✔
44
    assert Query.double.root_type == Query
4✔
45
    assert Query.double.name == "double"
4✔
46

47

48
def test_entrypoint__function__get_field_type() -> None:
4✔
49
    class Query(RootType):
4✔
50
        @Entrypoint
4✔
51
        def double(self, number: int) -> int:
4✔
52
            return number * 2
×
53

54
    field_type = Query.double.get_field_type()
4✔
55
    assert field_type == GraphQLNonNull(GraphQLInt)
4✔
56

57

58
def test_entrypoint__function__get_field_arguments() -> None:
4✔
59
    class Query(RootType):
4✔
60
        @Entrypoint
4✔
61
        def double(self, number: int) -> int:
4✔
62
            return number * 2
×
63

64
    arguments = Query.double.get_field_arguments()
4✔
65
    assert arguments == {"number": GraphQLArgument(GraphQLNonNull(GraphQLInt), out_name="number")}
4✔
66

67

68
def test_entrypoint__function__get_resolver() -> None:
4✔
69
    class Query(RootType):
4✔
70
        @Entrypoint
4✔
71
        def double(self, number: int) -> int:
4✔
72
            return number * 2
×
73

74
    resolver = Query.double.get_resolver()
4✔
75
    assert isinstance(resolver, EntrypointFunctionResolver)
4✔
76

77

78
def test_entrypoint__function__as_graphql_field() -> None:
4✔
79
    class Query(RootType):
4✔
80
        @Entrypoint
4✔
81
        def double(self, number: int) -> int:
4✔
82
            """Description."""
83
            return number * 2
×
84

85
    graphql_field = Query.double.as_graphql_field()
4✔
86

87
    assert graphql_field.type == GraphQLNonNull(GraphQLInt)
4✔
88
    assert graphql_field.args == {"number": GraphQLArgument(GraphQLNonNull(GraphQLInt), out_name="number")}
4✔
89
    assert isinstance(graphql_field.resolve, EntrypointFunctionResolver)
4✔
90
    assert graphql_field.description == "Description."
4✔
91
    assert graphql_field.deprecation_reason is None
4✔
92
    assert graphql_field.extensions == {"undine_entrypoint": Query.double}
4✔
93

94

95
def test_entrypoint__function__decorator_arguments() -> None:
4✔
96
    class Query(RootType):
4✔
97
        @Entrypoint(deprecation_reason="Use something else.")
4✔
98
        def double(self, number: int) -> int:
4✔
99
            return number * 2
×
100

101
    assert Query.double.deprecation_reason == "Use something else."
4✔
102

103

104
def test_entrypoint__function__directives__root_type() -> None:
4✔
105
    class ValueDirective(Directive, locations=[DirectiveLocation.OBJECT], schema_name="value"):
4✔
106
        value = DirectiveArgument(GraphQLNonNull(GraphQLString))
4✔
107

108
    directives: list[Directive] = [ValueDirective(value="foo")]
4✔
109

110
    class Query(RootType, directives=directives):
4✔
111
        @Entrypoint
4✔
112
        def double(self, number: int) -> int:
4✔
113
            return number * 2
×
114

115
    assert Query.__directives__ == directives
4✔
116

117
    assert str(Query) == cleandoc(
4✔
118
        """
119
        type Query @value(value: "foo") {
120
          double(
121
            number: Int!
122
          ): Int!
123
        }
124
        """
125
    )
126

127

128
def test_entrypoint__function__directives__root_type__not_applicable() -> None:
4✔
129
    class ValueDirective(Directive, locations=[DirectiveLocation.ENUM_VALUE], schema_name="value"):
4✔
130
        value = DirectiveArgument(GraphQLNonNull(GraphQLString))
4✔
131

132
    with pytest.raises(DirectiveLocationError):
4✔
133

134
        class Query(RootType, directives=[ValueDirective(value="foo")]):
4✔
135
            @Entrypoint()
4✔
136
            def double(self, number: int) -> int:
4✔
137
                return number * 2
×
138

139

140
def test_entrypoint__function__directives__entrypoint() -> None:
4✔
141
    class ValueDirective(Directive, locations=[DirectiveLocation.FIELD_DEFINITION], schema_name="value"):
4✔
142
        value = DirectiveArgument(GraphQLNonNull(GraphQLString))
4✔
143

144
    directives: list[Directive] = [ValueDirective(value="foo")]
4✔
145

146
    class Query(RootType):
4✔
147
        @Entrypoint(directives=directives)
4✔
148
        def double(self, number: int) -> int:
4✔
149
            return number * 2
×
150

151
    assert Query.double.directives == directives
4✔
152

153
    assert str(Query) == cleandoc(
4✔
154
        """
155
        type Query {
156
          double(
157
            number: Int!
158
          ): Int! @value(value: "foo")
159
        }
160
        """
161
    )
162

163

164
def test_entrypoint__function__directives__entrypoint__not_applicable() -> None:
4✔
165
    class ValueDirective(Directive, locations=[DirectiveLocation.ENUM_VALUE], schema_name="value"):
4✔
166
        value = DirectiveArgument(GraphQLNonNull(GraphQLString))
4✔
167

168
    directives: list[Directive] = [ValueDirective(value="foo")]
4✔
169

170
    with pytest.raises(DirectiveLocationError):
4✔
171

172
        class Query(RootType):
4✔
173
            @Entrypoint(directives=directives)
4✔
174
            def double(self, number: int) -> int:
×
175
                return number * 2
×
176

177

178
def test_entrypoint__function__directives__decorator() -> None:
4✔
179
    class ValueDirective(Directive, locations=[DirectiveLocation.FIELD_DEFINITION], schema_name="value"):
4✔
180
        value = DirectiveArgument(GraphQLNonNull(GraphQLString))
4✔
181

182
    class Query(RootType):
4✔
183
        @ValueDirective(value="foo")
4✔
184
        @Entrypoint()
4✔
185
        def double(self, number: int) -> int:
4✔
186
            return number * 2
×
187

188
    assert Query.double.directives == [ValueDirective(value="foo")]
4✔
189

190
    assert str(Query) == cleandoc(
4✔
191
        """
192
        type Query {
193
          double(
194
            number: Int!
195
          ): Int! @value(value: "foo")
196
        }
197
        """
198
    )
199

200

201
def test_entrypoint__function__extensions__root_type() -> None:
4✔
202
    class Query(RootType, extensions={"foo": "bar"}):
4✔
203
        @Entrypoint
4✔
204
        def double(self, number: int) -> int:
4✔
205
            return number * 2
×
206

207
    assert Query.__extensions__ == {"foo": "bar", "undine_root_type": Query}
4✔
208

209

210
def test_entrypoint__function__extensions__entrypoint() -> None:
4✔
211
    class Query(RootType):
4✔
212
        @Entrypoint(extensions={"foo": "bar"})
4✔
213
        def double(self, number: int) -> int:
4✔
214
            return number * 2
×
215

216
    assert Query.double.extensions == {"foo": "bar", "undine_entrypoint": Query.double}
4✔
217

218

219
def test_entrypoint__function__str__root_type() -> None:
4✔
220
    class Query(RootType):
4✔
221
        @Entrypoint
4✔
222
        def double(self, number: int) -> int:
4✔
223
            return number * 2
×
224

225
    assert str(Query) == cleandoc(
4✔
226
        """
227
        type Query {
228
          double(
229
            number: Int!
230
          ): Int!
231
        }
232
        """
233
    )
234

235

236
def test_entrypoint__function__str__entrypoint() -> None:
4✔
237
    class Query(RootType):
4✔
238
        @Entrypoint
4✔
239
        def double(self, number: int) -> int:
4✔
240
            return number * 2
×
241

242
    assert str(Query.double) == cleandoc(
4✔
243
        """
244
        double(
245
          number: Int!
246
        ): Int!
247
        """
248
    )
249

250

251
def test_entrypoint__union_errors() -> None:
4✔
252
    class Query(RootType):
4✔
253
        @Entrypoint(errors=[GraphQLError])
4✔
254
        def example(self) -> int:
4✔
255
            return 0
×
256

257
    Query.example.errors = [GraphQLError]
4✔
258

259
    graphql_type = Query.example.get_field_type()
4✔
260

261
    assert isinstance(graphql_type, GraphQLNonNull)
4✔
262
    assert isinstance(graphql_type.of_type, GraphQLUnionType)
4✔
263
    assert graphql_type.of_type.name == "QueryExample"
4✔
264

265
    assert graphql_type.of_type.types[0].name == "QueryExampleValue"
4✔
266
    assert graphql_type.of_type.types[0].fields["value"]
4✔
267
    assert graphql_type.of_type.types[0].fields["value"].type == GraphQLNonNull(GraphQLInt)
4✔
268

269
    assert graphql_type.of_type.types[1].name == "GraphQLError"
4✔
270
    assert graphql_type.of_type.types[1].fields["message"]
4✔
271
    assert graphql_type.of_type.types[1].fields["message"].type == GraphQLNonNull(GraphQLString)
4✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc