Skip to content

Commit c1b1526

Browse files
authored
fix: use ruff check and format (#44)
* ci: add ruff (check & format), remove black - ruff check is fantastic - ruff format is a drop-in replacement for black (in particular the upcoming preview) the only places where ruff disagrees with black I agree with the former * ci: configure ruff - select all rules - disable the 4 rules globally that conflict with ruff format - disable certain rules on a per-file basis - assert is allowed in tests - we are using print in the unit tests to track execution * fix: ruff errors fix all errors detected by ruff after we turned on nearly all the rules * ci: configure vscode to use ruff helps find and fix ruff errors
1 parent 40e8fe2 commit c1b1526

File tree

14 files changed

+188
-173
lines changed

14 files changed

+188
-173
lines changed

.vscode/settings.json

+5-9
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
{
2-
"python.formatting.provider": "black",
3-
"python.linting.pylintEnabled": true,
4-
"python.linting.mypyEnabled": true,
5-
"python.linting.mypyArgs": [
6-
"--show-column-numbers",
7-
"--no-pretty",
8-
"--strict"
9-
],
102
"python.testing.pytestArgs": [
113
"-sqx",
124
"tests"
135
],
146
"python.testing.unittestEnabled": false,
157
"python.testing.pytestEnabled": true,
16-
"python.envFile": "${workspaceFolder}/.env"
8+
"python.envFile": "${workspaceFolder}/.env",
9+
"[python]": {
10+
"editor.formatOnSave": true,
11+
"editor.defaultFormatter": "charliermarsh.ruff"
12+
}
1713
}

example/src/example/server/__main__.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44

55
from .processor import app
66

7-
87
if __name__ == "__main__":
98
logging.basicConfig(
109
format="%(asctime)s %(name)s %(filename)s:%(lineno)d - %(message)s",
1110
level=logging.INFO,
1211
)
13-
app.run(host="0.0.0.0", port=80)
12+
app.run(host="0.0.0.0", port=80) # noqa: S104

example/src/example/server/dba.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
"""DB (Postgres) Accessor."""
22

3-
from contextlib import contextmanager
3+
from __future__ import annotations
4+
45
import os
5-
from typing import Any, cast, Iterator, Optional
6+
from contextlib import contextmanager
7+
from typing import Any, Iterator, cast
68

79
import psycopg
810

9-
1011
DB_USER = "postgres"
1112
DB_PASSWORD = os.environ["POSTGRES_PASSWORD"]
1213
DB_HOST = "db-host"
@@ -16,7 +17,7 @@
1617

1718

1819
@contextmanager
19-
def get_cursor(autocommit: bool = False) -> Iterator[psycopg.Cursor[Optional[Record]]]:
20+
def get_cursor(autocommit: bool = False) -> Iterator[psycopg.Cursor[Record | None]]:
2021
"""Create cursor to postgres DB."""
2122
conn = psycopg.connect(
2223
autocommit=autocommit, user=DB_USER, password=DB_PASSWORD, host=DB_HOST
@@ -27,7 +28,7 @@ def get_cursor(autocommit: bool = False) -> Iterator[psycopg.Cursor[Optional[Rec
2728
yield cursor
2829

2930

30-
def get_operation(uuid: int) -> Optional[str]:
31+
def get_operation(uuid: int) -> str | None:
3132
"""Get operation for given uuid from operations table."""
3233
with get_cursor() as cursor:
3334
query = """

example/src/example/server/processor.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22

33
import logging
44

5-
from flask import Flask, jsonify, Response, request
5+
from flask import Flask, Response, jsonify, request
66

77
from . import dba
88

9-
109
logger = logging.getLogger(__name__)
1110
app = Flask(__name__)
1211

@@ -20,12 +19,10 @@ def process_test() -> Response:
2019

2120
@app.route("/compute", methods=["POST"])
2221
def process_compute() -> Response:
23-
"""The /compute end-point fetches operation corresponding to uuid and applies it."""
22+
"""Fetch operation corresponding to uuid and apply it."""
2423
payload = request.json
2524
logger.info("Request to /compute: %s", payload)
2625

27-
assert payload
28-
2926
uuid = payload["uuid"]
3027
value = payload["input"]
3128

example/tests/integration/conftest.py

+3-41
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,11 @@
11
"""Fixtures for integration tests."""
22

33
from typing import Iterator
4-
import pytest
54

6-
# import dba
5+
import pytest
76

87

9-
@pytest.fixture
8+
@pytest.fixture()
109
def base_url() -> Iterator[str]:
1110
"""URL to flask server in composable environment."""
12-
yield "http://server"
13-
14-
15-
# @pytest.fixture(name="uuid")
16-
# def uuid_fixture() -> Iterator[int]:
17-
# """Yield the uuid used for testing."""
18-
# yield 1234
19-
20-
# @pytest.fixture(name="operation")
21-
# def operation_fixture(uuid: int) -> Iterator[str]:
22-
# """Bind uuid to operation string in DB."""
23-
# with dba.get_cursor(autocommit=True) as cursor:
24-
# operation = "identity"
25-
# query = """
26-
# INSERT
27-
# INTO operations
28-
# (
29-
# uuid,
30-
# operation
31-
# )
32-
# VALUES
33-
# (
34-
# %(uuid)s,
35-
# %(operation)s
36-
# )
37-
# """
38-
# cursor.execute(query, {"uuid": uuid, "operation": operation})
39-
40-
# yield operation
41-
42-
# with dba.get_cursor(autocommit=True) as cursor:
43-
# query = """
44-
# DELETE
45-
# FROM operations
46-
# WHERE
47-
# uuid=%(uuid)s
48-
# """
49-
# cursor.execute(query, {"uuid": uuid})
11+
return "http://server"

example/tests/integration/test_compute.py

+13-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
"""Test the compute end-point."""
22

33
import json
4+
45
import requests
56

6-
from .utils import base_url, operation, Uuid
7+
from .utils import Uuid, base_url, operation
8+
9+
HTTP_OK = 200
710

811

912
@operation.set("identity")
@@ -16,42 +19,44 @@ def test_compute_identity(uuid: Uuid) -> None:
1619
response = requests.post(f"{base_url}/compute", json=payload, timeout=5)
1720

1821
# THEN
19-
assert response.status_code == 200
22+
assert response.status_code == HTTP_OK
2023

2124
output = json.loads(response.text)
22-
assert output["result"] == 9 # Identity operation
25+
assert output["result"] == payload["input"] # Identity operation
2326

2427

2528
@operation.set("square")
2629
def test_compute_square(uuid: Uuid) -> None:
2730
"""Test the /compute end-point for a user with square operation."""
2831
# GIVEN
2932
payload = {"uuid": uuid, "input": 9}
33+
expected_result = 9 * 9 # square operation
3034

3135
# WHEN
3236
response = requests.post(f"{base_url}/compute", json=payload, timeout=5)
3337

3438
# THEN
35-
assert response.status_code == 200
39+
assert response.status_code == HTTP_OK
3640

3741
output = json.loads(response.text)
38-
assert output["result"] == 81 # square operation
42+
assert output["result"] == expected_result
3943

4044

4145
@operation.set("cube")
4246
def test_compute_cube(uuid: Uuid) -> None:
4347
"""Test the /compute end-point for a user with cube operation."""
4448
# GIVEN
4549
payload = {"uuid": uuid, "input": 9}
50+
expected_result = 9 * 9 * 9 # cube operation
4651

4752
# WHEN
4853
response = requests.post(f"{base_url}/compute", json=payload, timeout=5)
4954

5055
# THEN
51-
assert response.status_code == 200
56+
assert response.status_code == HTTP_OK
5257

5358
output = json.loads(response.text)
54-
assert output["result"] == 729 # cube operation
59+
assert output["result"] == expected_result
5560

5661

5762
# Note: No operation record in the DB
@@ -65,7 +70,7 @@ def test_compute_no_operation() -> None:
6570
response = requests.post(f"{base_url}/compute", json=payload, timeout=5)
6671

6772
# THEN
68-
assert response.status_code == 200
73+
assert response.status_code == HTTP_OK
6974

7075
output = json.loads(response.text)
7176
assert "error" in output

example/tests/integration/test_test_endpoint.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
"""Test the /test end-point in the server."""
22

33
import json
4+
45
import requests
56

67
from .utils import base_url
78

9+
HTTP_OK = 200
10+
811

912
def test_test_endpoint() -> None:
1013
"""Test the /test end-point in the server."""
@@ -15,7 +18,7 @@ def test_test_endpoint() -> None:
1518
response = requests.get(url, timeout=5)
1619

1720
# THEN
18-
assert response.status_code == 200
21+
assert response.status_code == HTTP_OK
1922
payload = json.loads(response.text)
2023

2124
assert payload["test"]["success"] is True

example/tests/integration/utils.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
"""Utilities for testing such as shared constants and fixtures."""
22

33
from typing import NewType, ParamSpec
4-
from example.server import dba
54

6-
from testing.fixtures import fixture, FixtureDefinition
5+
from testing.fixtures import FixtureDefinition, fixture
6+
7+
from example.server import dba
78

89
P = ParamSpec("P")
910
Uuid = NewType("Uuid", int)

pyproject.toml

+21-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,27 @@ version_toml = [
4949
branch = "main"
5050
upload_to_release = true # auto create Github Release
5151

52+
[tool.ruff]
53+
select = ["ALL"]
54+
ignore = [
55+
"D203", # First 4 rules are mutually incompatible and incompatible with ruff format
56+
"D212",
57+
"COM812",
58+
"ISC001",
59+
"FBT", # Boolean values in function signatures
60+
"ANN101", # Annotate `self` parameter of class methods
61+
]
62+
63+
[tool.ruff.per-file-ignores]
64+
"**/tests/**/*.py" = [
65+
"S101" # assert is allowed in tests
66+
]
67+
"tests/unit/*.py" = [
68+
"T201" # we are using print to track execution path
69+
]
70+
5271
[tool.pylint.'MESSAGE CONTROL']
5372
disable = [
54-
"invalid-name"
73+
"invalid-name",
74+
"no-else-raise", # conflicts with ruff
5575
]

0 commit comments

Comments
 (0)