Skip to content

Commit 16226d7

Browse files
mesh-1697: switch to ruff to match other mesh repos
1 parent 7ad8c2f commit 16226d7

11 files changed

Lines changed: 223 additions & 334 deletions

.flake8

Lines changed: 0 additions & 3 deletions
This file was deleted.

Makefile

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,23 @@ install-hooks:
1414
test:
1515
@echo disable for spec only
1616

17-
lint:
17+
black:
18+
poetry run black .
19+
20+
black-check:
21+
poetry run black . --check
22+
23+
ruff: black
24+
poetry run ruff --fix --show-fixes .
25+
26+
ruff-check:
27+
poetry run ruff .
28+
29+
ruff-ci:
30+
poetry run ruff --output-format=github .
31+
32+
lint: ruff
1833
npm run lint
19-
poetry run flake8
2034

2135
publish:
2236
npm run publish 2> /dev/null

poetry.lock

Lines changed: 102 additions & 257 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
[project]
2+
name="mesh_api_specification"
23
python = "^3.8"
34

45

@@ -31,10 +32,64 @@ gitpython = "^3.1.30"
3132

3233

3334
[tool.poetry.dev-dependencies]
34-
flake8 = "^3.7.9"
35-
black = "^19.10b0"
35+
ruff = "^0.0.291"
36+
black = "^23.9.1"
3637
pip-licenses = "^2.0.1"
3738
jinja2 = "^2.11.2"
3839

3940

4041
[tool.poetry.scripts]
42+
43+
[tool.poetry.group.dev.dependencies]
44+
black = "^23.9.1"
45+
46+
[tool.black]
47+
line-length = 120
48+
target-version = ['py38', 'py39', 'py310', 'py311']
49+
include = '\.pyi?$'
50+
#extend-exclude = '''
51+
#/(
52+
# # The following are specific to Black, you probably don't want those.
53+
# | blib2to3
54+
# | tests/data
55+
# | profiling
56+
#)/
57+
#'''
58+
59+
[tool.ruff]
60+
select = [
61+
# See https://beta.ruff.rs/docs/rules/ for a full list
62+
"E", # pycodestyle errors
63+
"W", # pycodestyle warnings
64+
"F", # pyflakes
65+
"I", # isort
66+
"C", # flake8-comprehensions
67+
"B", # flake8-bugbear
68+
"Q", # flake8-quotes
69+
"YTT", # flake8-2020
70+
"RSE", # flake8-raise
71+
"T10", # flake8-debugger
72+
"ISC", # flake8-implicit-str-concat
73+
"ICN", # flake8-import-conventions
74+
"PIE", # flake8-pie
75+
"EXE", # flake8-executable
76+
"A", # flake8-builtins
77+
"UP", # pyupgrade
78+
"PT", # flake8-pytest-style
79+
"PERF", # Perflint #
80+
"RUF", # Ruff-specific rules
81+
"SIM", # flake8-simplify
82+
]
83+
src = ["."]
84+
ignore = [
85+
"PT004",
86+
]
87+
exclude = [
88+
".git",
89+
".venv",
90+
]
91+
unfixable = ["SIM112"]
92+
line-length = 120
93+
target-version = "py310"
94+
95+
[tool.ruff.per-file-ignores]

scripts/calculate_version.py

100644100755
Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616
+startversioning Reset version to v1.0.0-alpha
1717
"""
1818

19-
import os.path
2019
import itertools
20+
import os.path
21+
from itertools import pairwise
22+
2123
import git
2224
import semver
2325

24-
2526
SCRIPT_LOCATION = os.path.join(os.path.dirname(os.path.abspath(__file__)))
2627
REPO_ROOT = os.path.abspath(os.path.join(SCRIPT_LOCATION, ".."))
2728
REPO = git.Repo(REPO_ROOT)
@@ -33,9 +34,7 @@ def get_versionable_commits(repo):
3334
commits = [c for c in repo.iter_commits() if len(c.parents) == 1]
3435

3536
# If there is a marker to start versioning from, use it. Else, start from the first commit
36-
return list(
37-
itertools.takewhile(lambda c: "+startversioning" not in c.message, commits)
38-
)
37+
return list(itertools.takewhile(lambda c: "+startversioning" not in c.message, commits))
3938

4039

4140
def is_status_set_command(commit):
@@ -55,7 +54,7 @@ def is_minor_inc(commit):
5554

5655
def without_empty(commits):
5756
"""Takes a list of commits and returns a list without empty commits"""
58-
pairs = zip(commits, commits[1:])
57+
pairs = pairwise(commits)
5958

6059
for fst, snd in pairs:
6160
if fst.tree != snd.tree:
@@ -83,9 +82,7 @@ def calculate_version(base_major=1, base_minor=0, base_revision=0, base_pre="alp
8382
most_recent_message = status_sets[0].message.strip()
8483

8584
if most_recent_message.startswith("+setstatus "):
86-
pre = most_recent_message.split(" ")[
87-
1
88-
] # Take the first string after the command
85+
pre = most_recent_message.split(" ")[1] # Take the first string after the command
8986

9087
if most_recent_message == "+clearstatus":
9188
pre = None

scripts/generate_examples.py

Lines changed: 15 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
import json
1010
import os
1111
import os.path
12+
1213
from docopt import docopt
1314
from jsonpath_rw import parse
1415

1516

16-
def generate_resource_example(schema_dict, path=None):
17+
def generate_resource_example(schema_dict, path=None): # noqa: C901 - complexity 11 instead of 10.
1718
"""
1819
Generates resource examples from an OAS schema
1920
@@ -29,50 +30,34 @@ def generate_resource_example(schema_dict, path=None):
2930
if property_value["type"] == "array":
3031
if "oneOf" in property_value["items"]:
3132
example[property_name] = [
32-
generate_resource_example(t["properties"], path + [property_name])
33+
generate_resource_example(t["properties"], [*path, property_name])
3334
for t in property_value["items"]["oneOf"]
3435
]
3536
elif "anyOf" in property_value["items"]:
3637
example[property_name] = [
37-
generate_resource_example(t["properties"], path + [property_name])
38+
generate_resource_example(t["properties"], [*path, property_name])
3839
for t in property_value["items"]["anyOf"]
3940
]
4041
elif property_value["items"]["type"] == "object":
4142
example[property_name] = [
42-
generate_resource_example(
43-
property_value["items"]["properties"], path + [property_name]
44-
)
43+
generate_resource_example(property_value["items"]["properties"], [*path, property_name])
4544
]
4645
else:
4746
if {"example", "default"} & set(property_value.get("items", {}).keys()):
4847
items = property_value["items"]
49-
example[property_name] = [
50-
items.get("example", items.get("default"))
51-
]
52-
elif ("example" not in property_value) and (
53-
"default" not in property_value
54-
):
48+
example[property_name] = [items.get("example", items.get("default"))]
49+
elif ("example" not in property_value) and ("default" not in property_value):
5550
property_path = ".".join(path)
56-
raise RuntimeError(
57-
f"{property_path}.{property_name} has no example or default!"
58-
)
51+
raise RuntimeError(f"{property_path}.{property_name} has no example or default!")
5952
else:
60-
example[property_name] = property_value.get(
61-
"example", property_value.get("default")
62-
)
53+
example[property_name] = property_value.get("example", property_value.get("default"))
6354
elif property_value["type"] == "object":
64-
example[property_name] = generate_resource_example(
65-
property_value["properties"], path + [property_name]
66-
)
55+
example[property_name] = generate_resource_example(property_value["properties"], [*path, property_name])
6756
else:
6857
if ("example" not in property_value) and ("default" not in property_value):
6958
property_path = ".".join(path)
70-
raise RuntimeError(
71-
f"{property_path}.{property_name} has no example or default!"
72-
)
73-
example[property_name] = property_value.get(
74-
"example", property_value.get("default")
75-
)
59+
raise RuntimeError(f"{property_path}.{property_name} has no example or default!")
60+
example[property_name] = property_value.get("example", property_value.get("default"))
7661

7762
return example
7863

@@ -82,7 +67,7 @@ def main(arguments):
8267
arguments = docopt(__doc__, version="0")
8368

8469
# Load spec from file
85-
with open(arguments["SPEC_FILE"], "r") as spec_file:
70+
with open(arguments["SPEC_FILE"]) as spec_file:
8671
spec = json.loads(spec_file.read())
8772

8873
# Create default dir structure
@@ -95,18 +80,10 @@ def main(arguments):
9580
os.path.join(arguments["OUT_DIR"], "resources", component_name + ".json"),
9681
"w",
9782
) as out_file:
98-
out_file.write(
99-
json.dumps(
100-
generate_resource_example(
101-
component_spec["properties"], [component_name]
102-
)
103-
)
104-
)
83+
out_file.write(json.dumps(generate_resource_example(component_spec["properties"], [component_name])))
10584

10685
# Pull out responses
107-
match_expr = parse(
108-
"paths.*.*.(response|(responses.*)).content.*.(example|(examples.*.value))"
109-
)
86+
match_expr = parse("paths.*.*.(response|(responses.*)).content.*.(example|(examples.*.value))")
11087

11188
for match in match_expr.find(spec):
11289
if "patch" in str(match.full_path):

scripts/nhs_number_utils.py

100644100755
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,7 @@ def nhs_number_is_valid(nhs_number: str) -> bool:
5050

5151
def main():
5252
"""Main entrypoint"""
53-
parser = argparse.ArgumentParser(
54-
description="Validate NHS Numbers or generate check digit for a number"
55-
)
53+
parser = argparse.ArgumentParser(description="Validate NHS Numbers or generate check digit for a number")
5654
parser.add_argument(
5755
"operation",
5856
help="generate a check digit given 9-digit prefix, or validate a 10-digit NHS number",

scripts/set_version.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
Reads an openapi spec on stdin and adds the calculated version to it,
66
then prints it on stdout.
77
"""
8-
import sys
98
import json
9+
import sys
10+
1011
from calculate_version import calculate_version
1112

1213

scripts/template.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#!/usr/bin/env python
12
"""
23
template.py
34
@@ -15,9 +16,10 @@
1516
-f <path> --file=<path> Template from file at path.
1617
-e --env Replace from environment variables instead of JSON argument.
1718
"""
19+
import json
1820
import os
1921
import sys
20-
import json
22+
2123
from docopt import docopt
2224
from jinja2 import Template
2325

@@ -28,21 +30,21 @@ def replace(template, replacements):
2830

2931
def main(args):
3032
template = ""
31-
if args['--file']:
32-
with open(args['--file'], 'r') as template_file:
33+
if args["--file"]:
34+
with open(args["--file"]) as template_file:
3335
template = template_file.read()
3436
else:
3537
template = sys.stdin.read()
3638

3739
replacements = {}
38-
if args['<replacements>']:
39-
replacements = json.loads(args['<replacements>'])
40-
elif args['--env']:
40+
if args["<replacements>"]:
41+
replacements = json.loads(args["<replacements>"])
42+
elif args["--env"]:
4143
replacements = os.environ
4244

4345
sys.stdout.write(replace(template, replacements))
4446
sys.stdout.close()
4547

4648

4749
if __name__ == "__main__":
48-
main(docopt(__doc__, version='1'))
50+
main(docopt(__doc__, version="1"))

scripts/test_nhs_number_utils.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
Tests for nhs_number_utils module
33
"""
44
import unittest
5+
6+
import pytest
57
from nhs_number_utils import calculate_check_digit, nhs_number_is_valid
68

79
VALID_NHS_NUMBERS = (
@@ -28,26 +30,26 @@ class CheckDigitCalculatorTestCase(unittest.TestCase):
2830
def test_check_digits_calculate(self):
2931
"""Check that the check digit is correct"""
3032
for number in VALID_NHS_NUMBERS:
31-
self.assertEqual(calculate_check_digit(number[:-1]), int(number[9]))
33+
assert calculate_check_digit(number[:-1]) == int(number[9])
3234

3335
def test_too_short_nhs_numbers_raise_exception(self):
3436
"""Check that if the number is too short, an error is raised"""
35-
with self.assertRaisesRegex(ValueError, "Expecting nine digits"):
37+
with pytest.raises(ValueError, match="Expecting nine digits"):
3638
calculate_check_digit("12345678")
3739

3840
def test_too_long_nhs_numbers_raise_exception(self):
3941
"""Check that if the number is too long, an error is raised"""
40-
with self.assertRaisesRegex(ValueError, "Expecting nine digits"):
42+
with pytest.raises(ValueError, match="Expecting nine digits"):
4143
calculate_check_digit("1234567890")
4244

4345
def test_providing_something_not_a_number_raises_exception(self):
4446
"""Check that if the string is not numeric, an error is raised"""
45-
with self.assertRaisesRegex(ValueError, "nhs_number must comprise only digits"):
47+
with pytest.raises(ValueError, match="nhs_number must comprise only digits"):
4648
calculate_check_digit("A")
4749

4850
def test_invalid_nhs_number_detection(self):
4951
"""Check that invalid nhs numbers will be rejected"""
50-
with self.assertRaisesRegex(ValueError, "Number is invalid"):
52+
with pytest.raises(ValueError, match="Number is invalid"):
5153
calculate_check_digit("123456789")
5254

5355

@@ -57,24 +59,24 @@ class NhsNumberValidatorTestCase(unittest.TestCase):
5759
def test_valid_numbers_validate(self):
5860
"""Check that valid numbers validate"""
5961
for number in VALID_NHS_NUMBERS:
60-
self.assertTrue(nhs_number_is_valid(number))
62+
assert nhs_number_is_valid(number)
6163

6264
def test_invalid_nhs_numbers_are_detected(self):
6365
"""Check that nvalid numbers don't validate"""
6466
for number in INVALID_NHS_NUMBERS:
65-
self.assertFalse(nhs_number_is_valid(number))
67+
assert not nhs_number_is_valid(number)
6668

6769
def test_too_short_nhs_numbers_raise_exception(self):
6870
"""Check that too short nhs numbers will raise an exception"""
69-
with self.assertRaisesRegex(ValueError, "Expecting ten digits"):
71+
with pytest.raises(ValueError, match="Expecting ten digits"):
7072
nhs_number_is_valid("12345678")
7173

7274
def test_too_long_nhs_numbers_raise_exception(self):
7375
"""Check that too long nhs numbers will raise an exception"""
74-
with self.assertRaisesRegex(ValueError, "Expecting ten digits"):
76+
with pytest.raises(ValueError, match="Expecting ten digits"):
7577
nhs_number_is_valid("12345678901")
7678

7779
def test_providing_something_not_a_number_raises_exception(self):
7880
"""Check that non-numeric nhs numbers will raise an exception"""
79-
with self.assertRaisesRegex(ValueError, "nhs_number must comprise only digits"):
81+
with pytest.raises(ValueError, match="nhs_number must comprise only digits"):
8082
nhs_number_is_valid("A")

0 commit comments

Comments
 (0)