Skip to content

Commit 27cbbe5

Browse files
author
Mattia Baldari
committed
First ruff fix
1 parent ed14cc3 commit 27cbbe5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1245
-1048
lines changed

schemadiff/__init__.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,48 @@
1-
from typing import Union, List
1+
from typing import List, Union
22

3-
from graphql import GraphQLSchema as GQLSchema, is_schema
3+
from graphql import GraphQLSchema as GQLSchema
4+
from graphql import is_schema
45

56
from schemadiff.changes import Change
67
from schemadiff.diff.schema import Schema
8+
from schemadiff.formatting import format_diff, print_diff
79
from schemadiff.schema_loader import SchemaLoader
8-
from schemadiff.formatting import print_diff, format_diff
910
from schemadiff.validation import validate_changes
1011

11-
1212
SDL = str # Alias for string describing schema through schema definition language
1313

1414

15-
def diff(old_schema: Union[SDL, GQLSchema], new_schema: Union[SDL, GQLSchema]) -> List[Change]:
16-
"""Compare two graphql schemas highlighting dangerous and breaking changes.
15+
def diff(old_schema: SDL | GQLSchema, new_schema: SDL | GQLSchema) -> list[Change]:
16+
"""
17+
Compare two graphql schemas highlighting dangerous and breaking changes.
1718
1819
Returns:
1920
changes (List[Change]): List of differences between both schemas with details about each change
21+
2022
"""
2123
first = SchemaLoader.from_sdl(old_schema) if not is_schema(old_schema) else old_schema
2224
second = SchemaLoader.from_sdl(new_schema) if not is_schema(new_schema) else new_schema
2325
return Schema(first, second).diff()
2426

2527

2628
def diff_from_file(schema_file: str, other_schema_file: str):
27-
"""Compare two graphql schema files highlighting dangerous and breaking changes.
29+
"""
30+
Compare two graphql schema files highlighting dangerous and breaking changes.
2831
2932
Returns:
3033
changes (List[Change]): List of differences between both schemas with details about each change
34+
3135
"""
3236
first = SchemaLoader.from_file(schema_file)
3337
second = SchemaLoader.from_file(other_schema_file)
3438
return Schema(first, second).diff()
3539

3640

3741
__all__ = [
38-
'diff',
39-
'diff_from_file',
40-
'format_diff',
41-
'print_diff',
42-
'validate_changes',
43-
'Change',
42+
"Change",
43+
"diff",
44+
"diff_from_file",
45+
"format_diff",
46+
"print_diff",
47+
"validate_changes",
4448
]

schemadiff/__main__.py

Lines changed: 52 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import sys
21
import argparse
2+
import sys
33

44
from schemadiff.allow_list import read_allowed_changes
55
from schemadiff.diff.schema import Schema
6-
from schemadiff.schema_loader import SchemaLoader
76
from schemadiff.formatting import print_diff, print_json
7+
from schemadiff.schema_loader import SchemaLoader
88
from schemadiff.validation import rules_list, validate_changes
99

1010

@@ -14,32 +14,55 @@ def cli():
1414

1515

1616
def parse_args(arguments):
17-
parser = argparse.ArgumentParser(description='Schema comparator')
18-
parser.add_argument('-o', '--old-schema',
19-
dest='old_schema',
20-
type=argparse.FileType('r', encoding='UTF-8'),
21-
help='Path to old graphql schema file',
22-
required=True)
23-
parser.add_argument('-n', '--new-schema',
24-
dest='new_schema',
25-
type=argparse.FileType('r', encoding='UTF-8'),
26-
help='Path to new graphql schema file',
27-
required=True)
28-
parser.add_argument('-j', '--as-json',
29-
action='store_true',
30-
help='Output a detailed summary of changes in json format',
31-
required=False)
32-
parser.add_argument('-a', '--allow-list',
33-
type=argparse.FileType('r', encoding='UTF-8'),
34-
help='Path to the allowed list of changes')
35-
parser.add_argument('-t', '--tolerant',
36-
action='store_true',
37-
help="Tolerant mode. Error out only if there's a breaking change but allow dangerous changes")
38-
parser.add_argument('-s', '--strict',
39-
action='store_true',
40-
help="Strict mode. Error out on dangerous and breaking changes.")
41-
parser.add_argument('-r', '--validation-rules', choices=rules_list(), nargs='*',
42-
help="Evaluate rules mode. Error out on changes that fail some validation rule.")
17+
parser = argparse.ArgumentParser(description="Schema comparator")
18+
parser.add_argument(
19+
"-o",
20+
"--old-schema",
21+
dest="old_schema",
22+
type=argparse.FileType("r", encoding="UTF-8"),
23+
help="Path to old graphql schema file",
24+
required=True,
25+
)
26+
parser.add_argument(
27+
"-n",
28+
"--new-schema",
29+
dest="new_schema",
30+
type=argparse.FileType("r", encoding="UTF-8"),
31+
help="Path to new graphql schema file",
32+
required=True,
33+
)
34+
parser.add_argument(
35+
"-j",
36+
"--as-json",
37+
action="store_true",
38+
help="Output a detailed summary of changes in json format",
39+
required=False,
40+
)
41+
parser.add_argument(
42+
"-a",
43+
"--allow-list",
44+
type=argparse.FileType("r", encoding="UTF-8"),
45+
help="Path to the allowed list of changes",
46+
)
47+
parser.add_argument(
48+
"-t",
49+
"--tolerant",
50+
action="store_true",
51+
help="Tolerant mode. Error out only if there's a breaking change but allow dangerous changes",
52+
)
53+
parser.add_argument(
54+
"-s",
55+
"--strict",
56+
action="store_true",
57+
help="Strict mode. Error out on dangerous and breaking changes.",
58+
)
59+
parser.add_argument(
60+
"-r",
61+
"--validation-rules",
62+
choices=rules_list(),
63+
nargs="*",
64+
help="Evaluate rules mode. Error out on changes that fail some validation rule.",
65+
)
4366

4467
return parser.parse_args(arguments)
4568

@@ -79,5 +102,5 @@ def exit_code(changes, strict, some_change_is_restricted, tolerant) -> int:
79102
return exit_code
80103

81104

82-
if __name__ == '__main__':
105+
if __name__ == "__main__":
83106
sys.exit(cli())

schemadiff/allow_list.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44

55

66
class InvalidAllowlist(Exception):
7-
"""Exception raised when the user provides an invalid json file of allowed changes"""
7+
"""Exception raised when the user provides an invalid json file of allowed changes."""
88

99

1010
def read_allowed_changes(file_content):
11-
"""Read a json file that defines a mapping of changes checksums to the reasons of why it is allowed.
11+
"""
12+
Read a json file that defines a mapping of changes checksums to the reasons of why it is allowed.
1213
1314
Compliant formats:
1415
{
@@ -36,8 +37,8 @@ def read_allowed_changes(file_content):
3637
if not isinstance(allowlist, dict):
3738
raise InvalidAllowlist("Allowlist must be a mapping.")
3839

39-
CHECKSUM_REGEX = re.compile(r'[a-fA-F0-9]{32}')
40-
if any(not CHECKSUM_REGEX.match(checksum) for checksum in allowlist.keys()):
40+
CHECKSUM_REGEX = re.compile(r"[a-fA-F0-9]{32}")
41+
if any(not CHECKSUM_REGEX.match(checksum) for checksum in allowlist):
4142
raise InvalidAllowlist("All keys must be a valid md5 checksum")
4243

4344
return allowlist

schemadiff/changes/__init__.py

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import hashlib
22
import json
3-
from abc import abstractmethod, ABC
3+
from abc import ABC, abstractmethod
44
from enum import Enum
55
from typing import Optional
66

77
from attr import dataclass
8-
from graphql import is_wrapping_type, is_non_null_type, is_list_type
8+
from graphql import is_list_type, is_non_null_type, is_wrapping_type
99

1010

1111
class CriticalityLevel(Enum):
12-
NonBreaking = 'NON_BREAKING'
13-
Dangerous = 'DANGEROUS'
14-
Breaking = 'BREAKING'
12+
NonBreaking = "NON_BREAKING"
13+
Dangerous = "DANGEROUS"
14+
Breaking = "BREAKING"
1515

1616

1717
@dataclass(repr=False)
@@ -21,26 +21,27 @@ class Criticality:
2121

2222
@classmethod
2323
def breaking(cls, reason):
24-
"""Helper constructor of a breaking change"""
24+
"""Helper constructor of a breaking change."""
2525
return cls(level=CriticalityLevel.Breaking, reason=reason)
2626

2727
@classmethod
2828
def dangerous(cls, reason):
29-
"""Helper constructor of a dangerous change"""
29+
"""Helper constructor of a dangerous change."""
3030
return cls(level=CriticalityLevel.Dangerous, reason=reason)
3131

3232
@classmethod
3333
def safe(cls, reason="This change won't break any preexisting query"):
34-
"""Helper constructor of a safe change"""
34+
"""Helper constructor of a safe change."""
3535
return cls(level=CriticalityLevel.NonBreaking, reason=reason)
3636

37-
def __repr__(self):
37+
def __repr__(self) -> str:
3838
# Replace repr because of attrs bug https://github.com/python-attrs/attrs/issues/95
3939
return f"Criticality(level={self.level}, reason={self.reason})"
4040

4141

4242
def is_safe_type_change(old_type, new_type) -> bool:
43-
"""Depending on the old an new type, a field type change may be breaking, dangerous or safe
43+
"""
44+
Depending on the old an new type, a field type change may be breaking, dangerous or safe.
4445
4546
* If both fields are 'leafs' in the sense they don't wrap an inner type, just compare their type.
4647
* If the new type has a non-null constraint, check that it was already non-null and compare against the contained
@@ -59,14 +60,8 @@ def is_safe_type_change(old_type, new_type) -> bool:
5960
# If both types are lists, compare their inner type.
6061
# If the new type has a non-null constraint, compare with its inner type (may be a list or not)
6162
return (
62-
(
63-
is_list_type(new_type) and is_safe_type_change(old_type.of_type, new_type.of_type)
64-
)
65-
or
66-
(
67-
is_non_null_type(new_type) and is_safe_type_change(old_type, new_type.of_type)
68-
)
69-
)
63+
is_list_type(new_type) and is_safe_type_change(old_type.of_type, new_type.of_type)
64+
) or (is_non_null_type(new_type) and is_safe_type_change(old_type, new_type.of_type))
7065

7166
return False
7267

@@ -86,16 +81,17 @@ def is_safe_change_for_input_value(old_type, new_type):
8681

8782

8883
class Change(ABC):
89-
"""Common interface of all schema changes
90-
84+
"""
85+
Common interface of all schema changes.
86+
9187
This class offers the common operations and properties of all
9288
schema changes. You may use it as a type hint to get better
9389
suggestions in your editor of choice.
9490
"""
9591

9692
criticality: Criticality = None
9793

98-
restricted: Optional[str] = None
94+
restricted: str | None = None
9995
"""Descriptive message only present when a change was restricted"""
10096

10197
@property
@@ -116,12 +112,12 @@ def safe(self) -> bool:
116112
@property
117113
@abstractmethod
118114
def message(self) -> str:
119-
"""Formatted change message"""
115+
"""Formatted change message."""
120116

121117
@property
122118
@abstractmethod
123119
def path(self) -> str:
124-
"""Path to the affected schema member"""
120+
"""Path to the affected schema member."""
125121

126122
def __repr__(self) -> str:
127123
return f"Change(criticality={self.criticality!r}, message={self.message!r}, path={self.path!r})"
@@ -130,22 +126,22 @@ def __str__(self) -> str:
130126
return self.message
131127

132128
def to_dict(self) -> dict:
133-
"""Get detailed representation of a change"""
129+
"""Get detailed representation of a change."""
134130
return {
135-
'message': self.message,
136-
'path': self.path,
137-
'is_safe_change': self.safe,
138-
'criticality': {
139-
'level': self.criticality.level.value,
140-
'reason': self.criticality.reason
131+
"message": self.message,
132+
"path": self.path,
133+
"is_safe_change": self.safe,
134+
"criticality": {
135+
"level": self.criticality.level.value,
136+
"reason": self.criticality.reason,
141137
},
142-
'checksum': self.checksum(),
138+
"checksum": self.checksum(),
143139
}
144140

145141
def to_json(self) -> str:
146-
"""Get detailed representation of a change as a json string"""
142+
"""Get detailed representation of a change as a json string."""
147143
return json.dumps(self.to_dict())
148144

149145
def checksum(self) -> str:
150-
"""Get and identifier of a change. Used for allowlisting changes"""
151-
return hashlib.md5(self.message.encode('utf-8')).hexdigest()
146+
"""Get and identifier of a change. Used for allowlisting changes."""
147+
return hashlib.md5(self.message.encode("utf-8")).hexdigest()

schemadiff/changes/argument.py

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,23 @@
22

33

44
class FieldAbstractArgumentChange(Change):
5-
def __init__(self, parent_type, field, arg_name, old_arg, new_arg):
5+
def __init__(self, parent_type, field, arg_name, old_arg, new_arg) -> None:
66
self.parent = parent_type
77
self.field_name = field
88
self.arg_name = arg_name
99
self.old_arg = old_arg
1010
self.new_arg = new_arg
1111

1212
@property
13-
def path(self):
13+
def path(self) -> str:
1414
return f"{self.parent.name}.{self.field_name}"
1515

1616

1717
class FieldArgumentDescriptionChanged(FieldAbstractArgumentChange):
18-
1918
criticality = Criticality.safe()
2019

2120
@property
22-
def message(self):
21+
def message(self) -> str:
2322
return (
2423
f"Description for argument `{self.arg_name}` on field `{self.parent}.{self.field_name}` "
2524
f"changed from `{self.old_arg.description}` to `{self.new_arg.description}`"
@@ -33,27 +32,26 @@ class FieldArgumentDefaultValueChanged(FieldAbstractArgumentChange):
3332
)
3433

3534
@property
36-
def message(self):
35+
def message(self) -> str:
3736
return (
3837
f"Default value for argument `{self.arg_name}` on field `{self.parent}.{self.field_name}` "
3938
f"changed from `{self.old_arg.default_value!r}` to `{self.new_arg.default_value!r}`"
4039
)
4140

4241

4342
class FieldArgumentTypeChanged(FieldAbstractArgumentChange):
44-
45-
def __init__(self, parent_type, field, arg_name, old_arg, new_arg):
43+
def __init__(self, parent_type, field, arg_name, old_arg, new_arg) -> None:
4644
super().__init__(parent_type, field, arg_name, old_arg, new_arg)
4745
self.criticality = (
48-
Criticality.safe()
49-
if is_safe_change_for_input_value(old_arg.type, new_arg.type)
50-
else Criticality.breaking(
51-
"Changing the type of a field's argument can break existing queries that use this argument."
52-
)
46+
Criticality.safe()
47+
if is_safe_change_for_input_value(old_arg.type, new_arg.type)
48+
else Criticality.breaking(
49+
"Changing the type of a field's argument can break existing queries that use this argument."
50+
)
5351
)
5452

5553
@property
56-
def message(self):
54+
def message(self) -> str:
5755
return (
5856
f"Type for argument `{self.arg_name}` on field `{self.parent}.{self.field_name}` "
5957
f"changed from `{self.old_arg.type}` to `{self.new_arg.type}`"

0 commit comments

Comments
 (0)