Skip to content

Commit b0f9af7

Browse files
committed
Added Deprecated directive. Commit: graphql/graphql-js@5375c9b
1 parent c646fca commit b0f9af7

File tree

9 files changed

+144
-42
lines changed

9 files changed

+144
-42
lines changed

graphql/__init__.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,14 @@
7676
# Directive definition
7777
GraphQLDirective,
7878

79-
# Built-in directives
79+
# Built-in directives defined by the Spec
80+
specified_directives,
8081
GraphQLSkipDirective,
8182
GraphQLIncludeDirective,
83+
GraphQLDeprecatedDirective,
84+
85+
# Constant Deprecation Reason
86+
DEFAULT_DEPRECATION_REASON,
8287

8388
# GraphQL Types for introspection.
8489
__Schema,
@@ -215,8 +220,11 @@
215220
'GraphQLString',
216221
'GraphQLUnionType',
217222
'GraphQLDirective',
223+
'specified_directives',
218224
'GraphQLSkipDirective',
219225
'GraphQLIncludeDirective',
226+
'GraphQLDeprecatedDirective',
227+
'DEFAULT_DEPRECATION_REASON',
220228
'TypeKind',
221229
'DirectiveLocation',
222230
'__Schema',

graphql/execution/values.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def get_variable_values(schema, definition_asts, inputs):
2929
return values
3030

3131

32-
def get_argument_values(arg_defs, arg_asts, variables):
32+
def get_argument_values(arg_defs, arg_asts, variables=None):
3333
"""Prepares an object map of argument values given a list of argument
3434
definitions and list of argument AST nodes."""
3535
if not arg_defs:

graphql/type/__init__.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,14 @@
3030
# Directive definition
3131
GraphQLDirective,
3232

33-
# Built-in directives
33+
# Built-in directives defined by the Spec
34+
specified_directives,
3435
GraphQLSkipDirective,
35-
GraphQLIncludeDirective
36+
GraphQLIncludeDirective,
37+
GraphQLDeprecatedDirective,
38+
39+
# Constant Deprecation Reason
40+
DEFAULT_DEPRECATION_REASON,
3641
)
3742
from .scalars import ( # no import order
3843
GraphQLInt,

graphql/type/directives.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from ..utils.assert_valid_name import assert_valid_name
44
from .definition import (GraphQLArgument, GraphQLArgumentDefinition,
55
GraphQLNonNull, is_input_type)
6-
from .scalars import GraphQLBoolean
6+
from .scalars import GraphQLBoolean, GraphQLString
77

88

99
class DirectiveLocation(object):
@@ -74,9 +74,10 @@ def __init__(self, name, description=None, args=None, locations=None):
7474
default_value=_arg.default_value,
7575
))
7676

77-
77+
"""Used to conditionally include fields or fragments."""
7878
GraphQLIncludeDirective = GraphQLDirective(
7979
name='include',
80+
description='Directs the executor to include this field or fragment only when the `if` argument is true.',
8081
args={
8182
'if': GraphQLArgument(
8283
type=GraphQLNonNull(GraphQLBoolean),
@@ -90,8 +91,10 @@ def __init__(self, name, description=None, args=None, locations=None):
9091
]
9192
)
9293

94+
"""Used to conditionally skip (exclude) fields or fragments."""
9395
GraphQLSkipDirective = GraphQLDirective(
9496
name='skip',
97+
description='Directs the executor to skip this field or fragment when the `if` argument is true.',
9598
args={
9699
'if': GraphQLArgument(
97100
type=GraphQLNonNull(GraphQLBoolean),
@@ -104,3 +107,31 @@ def __init__(self, name, description=None, args=None, locations=None):
104107
DirectiveLocation.INLINE_FRAGMENT,
105108
]
106109
)
110+
111+
"""Constant string used for default reason for a deprecation."""
112+
DEFAULT_DEPRECATION_REASON = 'No longer supported'
113+
114+
"""Used to declare element of a GraphQL schema as deprecated."""
115+
GraphQLDeprecatedDirective = GraphQLDirective(
116+
name='deprecated',
117+
description='Marks an element of a GraphQL schema as no longer supported.',
118+
args={
119+
'reason': GraphQLArgument(
120+
type=GraphQLString,
121+
description=('Explains why this element was deprecated, usually also including a suggestion for how to'
122+
'access supported similar data. Formatted in [Markdown]'
123+
'(https://daringfireball.net/projects/markdown/).'),
124+
default_value=DEFAULT_DEPRECATION_REASON
125+
),
126+
},
127+
locations=[
128+
DirectiveLocation.FIELD_DEFINITION,
129+
DirectiveLocation.ENUM_VALUE,
130+
]
131+
)
132+
133+
specified_directives = [
134+
GraphQLIncludeDirective,
135+
GraphQLSkipDirective,
136+
GraphQLDeprecatedDirective
137+
]

graphql/type/schema.py

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
from .definition import (GraphQLInputObjectType, GraphQLInterfaceType,
66
GraphQLList, GraphQLNonNull, GraphQLObjectType,
77
GraphQLUnionType)
8-
from .directives import (GraphQLDirective, GraphQLIncludeDirective,
9-
GraphQLSkipDirective)
8+
from .directives import (GraphQLDirective, specified_directives)
109
from .introspection import IntrospectionSchema
1110

1211

@@ -20,20 +19,19 @@ class GraphQLSchema(object):
2019
2120
MyAppSchema = GraphQLSchema(
2221
query=MyAppQueryRootType,
23-
mutation=MyAppMutationRootType
22+
mutation=MyAppMutationRootType,
2423
)
2524
2625
Note: If an array of `directives` are provided to GraphQLSchema, that will be
2726
the exact list of directives represented and allowed. If `directives` is not
28-
provided then a default set of the built-in `[ @include, @skip ]` directives
29-
will be used. If you wish to provide *additional* directives to these
30-
built-ins, you must explicitly declare them. Example:
31-
32-
directives: [
33-
myCustomDirective,
34-
GraphQLIncludeDirective,
35-
GraphQLSkipDirective
36-
]
27+
provided then a default set of the specified directives (e.g. @include and
28+
@skip) will be used. If you wish to provide *additional* directives to these
29+
specified directives, you must explicitly declare them. Example:
30+
31+
MyAppSchema = GraphQLSchema(
32+
...
33+
directives=specified_directives.extend([MyCustomerDirective]),
34+
)
3735
"""
3836
__slots__ = '_query', '_mutation', '_subscription', '_type_map', '_directives', '_implementations', '_possible_type_map'
3937

@@ -55,10 +53,7 @@ def __init__(self, query, mutation=None, subscription=None, directives=None, typ
5553
self._mutation = mutation
5654
self._subscription = subscription
5755
if directives is None:
58-
directives = [
59-
GraphQLIncludeDirective,
60-
GraphQLSkipDirective
61-
]
56+
directives = specified_directives
6257

6358
assert all(isinstance(d, GraphQLDirective) for d in directives), \
6459
'Schema directives must be List[GraphQLDirective] if provided but got: {}.'.format(

graphql/utils/build_ast_schema.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88
GraphQLInt, GraphQLInterfaceType, GraphQLList,
99
GraphQLNonNull, GraphQLObjectType, GraphQLScalarType,
1010
GraphQLSchema, GraphQLSkipDirective, GraphQLString,
11-
GraphQLUnionType)
11+
GraphQLUnionType, GraphQLDeprecatedDirective)
1212
from ..type.introspection import (__Directive, __DirectiveLocation,
1313
__EnumValue, __Field, __InputValue, __Schema,
1414
__Type, __TypeKind)
1515
from ..utils.value_from_ast import value_from_ast
16+
from ..execution.values import get_argument_values
1617

1718

1819
def _build_wrapped_type(inner_type, input_type_ast):
@@ -179,7 +180,8 @@ def make_field_def_map(definition):
179180
return OrderedDict(
180181
(f.name.value, GraphQLField(
181182
type=produce_type_def(f.type),
182-
args=make_input_values(f.arguments, GraphQLArgument)
183+
args=make_input_values(f.arguments, GraphQLArgument),
184+
deprecation_reason=get_deprecation_reason(f.directives),
183185
))
184186
for f in definition.fields
185187
)
@@ -204,11 +206,11 @@ def make_interface_def(definition):
204206
)
205207

206208
def make_enum_def(definition):
209+
values = OrderedDict((v.name.value, GraphQLEnumValue(deprecation_reason=get_deprecation_reason(v.directives)))
210+
for v in definition.values)
207211
return GraphQLEnumType(
208212
name=definition.name.value,
209-
values=OrderedDict(
210-
(v.name.value, GraphQLEnumValue()) for v in definition.values
211-
)
213+
values=values
212214
)
213215

214216
def make_union_def(definition):
@@ -246,16 +248,20 @@ def make_input_object_def(definition):
246248
types = [type_def_named(definition.name.value) for definition in type_defs]
247249
directives = [get_directive(d) for d in directive_defs]
248250

249-
# If skip and include were not explicitly declared, add them.
251+
# If specified directive were not explicitly declared, add them.
250252
find_skip_directive = (directive.name for directive in directives if directive.name == 'skip')
251253
find_include_directive = (directive.name for directive in directives if directive.name == 'include')
254+
find_deprecated_directive = (directive.name for directive in directives if directive.name == 'deprecated')
252255

253256
if not next(find_skip_directive, None):
254257
directives.append(GraphQLSkipDirective)
255258

256259
if not next(find_include_directive, None):
257260
directives.append(GraphQLIncludeDirective)
258261

262+
if not next(find_deprecated_directive, None):
263+
directives.append(GraphQLDeprecatedDirective)
264+
259265
schema_kwargs = {'query': get_object_type(ast_map[query_type_name])}
260266

261267
if mutation_type_name:
@@ -271,3 +277,15 @@ def make_input_object_def(definition):
271277
schema_kwargs['types'] = types
272278

273279
return GraphQLSchema(**schema_kwargs)
280+
281+
282+
def get_deprecation_reason(directives):
283+
deprecated_ast = next((directive for directive in directives
284+
if directive.name.value == GraphQLDeprecatedDirective.name),
285+
None)
286+
287+
if deprecated_ast:
288+
args = get_argument_values(GraphQLDeprecatedDirective.args, deprecated_ast.arguments)
289+
return args['reason']
290+
else:
291+
return None

graphql/utils/schema_printer.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from ..type.definition import (GraphQLEnumType, GraphQLInputObjectType,
33
GraphQLInterfaceType, GraphQLObjectType,
44
GraphQLScalarType, GraphQLUnionType)
5+
from ..type.directives import DEFAULT_DEPRECATION_REASON
56
from .ast_from_value import ast_from_value
67

78

@@ -14,7 +15,7 @@ def print_introspection_schema(schema):
1415

1516

1617
def is_spec_directive(directive_name):
17-
return directive_name in ('skip', 'include')
18+
return directive_name in ('skip', 'include', 'deprecated')
1819

1920

2021
def _is_defined_type(typename):
@@ -117,7 +118,7 @@ def _print_enum(type):
117118
'enum {} {{\n'
118119
'{}\n'
119120
'}}'
120-
).format(type.name, '\n'.join(' ' + v.name for v in type.get_values()))
121+
).format(type.name, '\n'.join(' ' + v.name + _print_deprecated(v) for v in type.get_values()))
121122

122123

123124
def _print_input_object(type):
@@ -129,7 +130,19 @@ def _print_input_object(type):
129130

130131

131132
def _print_fields(type):
132-
return '\n'.join(' {}{}: {}'.format(f.name, _print_args(f), f.type) for f in type.get_fields().values())
133+
return '\n'.join(' {}{}: {}{}'.format(f.name, _print_args(f), f.type, _print_deprecated(f))
134+
for f in type.get_fields().values())
135+
136+
137+
def _print_deprecated(field_or_enum_value):
138+
reason = field_or_enum_value.deprecation_reason
139+
140+
if reason is None:
141+
return ''
142+
elif reason in ('', DEFAULT_DEPRECATION_REASON):
143+
return ' @deprecated'
144+
else:
145+
return ' @deprecated(reason: {})'.format(print_ast(ast_from_value(reason)))
133146

134147

135148
def _print_args(field_or_directives):

0 commit comments

Comments
 (0)