Skip to content

Commit ce3f484

Browse files
authored
feat(api): Ruff import order (PLAN §3.7), Turbo lint:fix, editor integration (#14)
* feat(api): Ruff import order (PLAN §3.7), Turbo lint:fix, editor integration - Add Ruff 0.15.9 with I rules and known-first-party app; exclude generated OpenAPI - Wire lint to pnpm run build then ruff check; add lint:fix for api - Root turbo lint:fix (cache: false); web placeholder; root pnpm lint:fix script - Document import order in apps/api README; mark PLAN §3.7 complete - Recommend Ruff extension; Python codeActionsOnSave for fixAll/organizeImports Made-with: Cursor * chore(vscode): format settings.json (indent, trailing newline) Made-with: Cursor * fix(api): install dev extras in postinstall so Ruff is available for lint - postinstall: pip install -e ".[dev]" (matches Copilot review) - README: document that pnpm install pulls Ruff/pytest; clarify Import order prereqs Made-with: Cursor
1 parent cd7b7e9 commit ce3f484

11 files changed

Lines changed: 53 additions & 20 deletions

File tree

.vscode/extensions.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"recommendations": [
3+
"charliermarsh.ruff",
34
"ms-python.python",
45
"ms-python.vscode-pylance",
56
"redhat.vscode-yaml",

.vscode/settings.json

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
{
2-
"python.defaultInterpreterPath": "${workspaceFolder}/apps/api/.venv/bin/python",
3-
"python.terminal.activateEnvironment": true,
4-
"cSpell.words": [
5-
"dataclass",
6-
"dataclasses"
7-
]
8-
}
2+
"python.defaultInterpreterPath": "${workspaceFolder}/apps/api/.venv/bin/python",
3+
"python.terminal.activateEnvironment": true,
4+
"[python]": {
5+
"editor.codeActionsOnSave": {
6+
"source.fixAll.ruff": "explicit",
7+
"source.organizeImports.ruff": "explicit"
8+
}
9+
},
10+
"cSpell.words": ["dataclass", "dataclasses"]
11+
}

PLAN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Tasks and subtasks for building the bread-recipes app (SolidJS + Python REST + O
2121
- [x] **3.4** Implement REST handlers to match the OpenAPI spec (response shapes and status codes); keep behaviour aligned with the spec.
2222
- [x] **3.5** Generate Pydantic models from **`packages/openapi/openapi.yaml`** (e.g. **datamodel-code-generator**), commit generated output, and add CI that fails when the spec changes without regenerating (drift check).
2323
- [x] **3.6** Tests with 100% coverage and a coverage gate in CI for the API package; add `README.md` for install, run, and test commands.
24-
- [ ] **3.7** Select and configure a Python import-ordering tool (PEP 8–aligned; e.g. **Ruff**’s isort rules or **isort**), apply it across **`apps/api`**, and document how to run it (CI enforcement can align with §3.6 / §6.1).
24+
- [x] **3.7** Select and configure a Python import-ordering tool (PEP 8–aligned; e.g. **Ruff**’s isort rules or **isort**), apply it across **`apps/api`**, and document how to run it (CI enforcement can align with §3.6 / §6.1).
2525

2626
## 4. SolidJS front end
2727

apps/api/README.md

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,12 @@ FastAPI ASGI service: **`GET /health`**, **`GET /recipes`**, and **`GET /recipes
1515

1616
## Setup
1717

18-
From the **repository root**, **`pnpm install`** runs this package’s **`postinstall`**: create **`apps/api/.venv`** if it is missing, then **`pip install -e .`** inside it so **`datamodel-code-generator`** and the rest of the core dependencies are available to **`pnpm openapi:generate`**.
18+
From the **repository root**, **`pnpm install`** runs this package’s **`postinstall`**: create **`apps/api/.venv`** if it is missing, then **`pip install -e ".[dev]"`** so runtime dependencies (**`datamodel-code-generator`**, **FastAPI**, …) and **dev** tools (**`pytest`**, **`ruff`**, …) are available for **`pnpm openapi:generate`**, **`pnpm lint`**, **`pnpm test`**, and **`pnpm lint:fix`**.
1919

20-
For tests and optional dev tools, from **`apps/api`** with the venv activated:
21-
22-
```bash
23-
source .venv/bin/activate
24-
pip install -e ".[dev]"
25-
```
26-
27-
Alternatively, create the venv and install everything in one go manually:
20+
If you create the venv yourself (without **`pnpm install`**), install the editable package with dev extras:
2821

2922
```bash
23+
cd apps/api
3024
python3 -m venv .venv
3125
source .venv/bin/activate
3226
pip install -e ".[dev]"
@@ -48,6 +42,22 @@ This runs **`pytest`** with **line coverage** for the **`app`** package, **fails
4842

4943
Configuration lives in **`pyproject.toml`** (**`[tool.pytest.ini_options]`**, **`[tool.coverage.*]`**).
5044

45+
## Import order (Ruff / isort)
46+
47+
Imports are checked with **[Ruff](https://docs.astral.sh/ruff/)** using the **`I`** rules (PEP 8–style ordering compatible with **isort**). Configuration lives under **`[tool.ruff]`** in **`pyproject.toml`** (`known-first-party = ["app"]`; generated OpenAPI models under **`app/openapi/generated/`** are excluded). **Ruff** is a **dev** dependency; after **[Setup](#setup)** ( **`pnpm install`** or **`pip install -e ".[dev]"`** ), **`apps/api/.venv/bin/ruff`** is available.
48+
49+
Check (matches CI):
50+
51+
```bash
52+
pnpm lint
53+
```
54+
55+
Auto-fix import order:
56+
57+
```bash
58+
pnpm lint:fix
59+
```
60+
5161
## Run (development)
5262

5363
```bash

apps/api/app/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
from starlette.requests import Request
77
from starlette.responses import JSONResponse
88

9-
from app.routers.recipes.data_paths import resolve_recipes_json_path
109
from app.openapi.paths import resolve_openapi_spec_path
1110
from app.openapi.spec import load_openapi_info
1211
from app.routers import health_router, recipes_router
12+
from app.routers.recipes.data_paths import resolve_recipes_json_path
1313
from app.routers.recipes.exceptions import RecipeNotFoundError
1414
from app.routers.recipes.repository import StaticRecipeRepository
1515
from app.routers.recipes.state import RecipeAppState

apps/api/app/openapi/codegen.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
PythonVersion,
1010
generate,
1111
)
12+
1213
from app.openapi.paths import resolve_openapi_spec_path
1314

1415
_PKG = Path(__file__).resolve().parent

apps/api/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
"dev": ".venv/bin/python -m uvicorn app.main:app --reload --host 127.0.0.1 --port 8000",
88
"openapi:generate": ".venv/bin/python -m app.openapi.codegen",
99
"openapi:validate": "bash scripts/validate_openapi_generated.sh",
10-
"lint": ".venv/bin/python -m compileall -q app",
10+
"lint": "pnpm build && .venv/bin/ruff check app",
11+
"lint:fix": ".venv/bin/ruff check app --fix",
1112
"test": ".venv/bin/python -m pytest -v",
12-
"postinstall": "bash -e -c 'test -d .venv || python3 -m venv .venv; .venv/bin/python -m pip install -e .'"
13+
"postinstall": "bash -e -c 'test -d .venv || python3 -m venv .venv; .venv/bin/python -m pip install -e \".[dev]\"'"
1314
}
1415
}

apps/api/pyproject.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ dev = [
2020
"httpx==0.28.1",
2121
"pytest==8.3.5",
2222
"pytest-cov==6.0.0",
23+
"ruff==0.15.9",
2324
]
2425

2526
[tool.hatch.build.targets.wheel]
@@ -44,3 +45,14 @@ exclude_lines = [
4445
"if TYPE_CHECKING:",
4546
"^ *\\.\\.\\.$",
4647
]
48+
49+
[tool.ruff]
50+
target-version = "py312"
51+
src = ["app"]
52+
exclude = ["app/openapi/generated"]
53+
54+
[tool.ruff.lint]
55+
select = ["I"]
56+
57+
[tool.ruff.lint.isort]
58+
known-first-party = ["app"]

apps/web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"build": "node -e \"console.log('web: build placeholder')\"",
77
"dev": "node -e \"console.log('web: dev placeholder')\"",
88
"lint": "node -e \"console.log('web: lint placeholder')\"",
9+
"lint:fix": "node -e \"console.log('web: lint:fix placeholder')\"",
910
"openapi:generate": "node -e \"console.log('web: openapi:generate placeholder')\"",
1011
"openapi:validate": "node -e \"console.log('web: openapi:validate placeholder')\"",
1112
"test": "node -e \"console.log('web: test placeholder')\""

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"build": "turbo run build",
1212
"dev": "turbo run dev",
1313
"lint": "turbo run lint",
14+
"lint:fix": "turbo run lint:fix",
1415
"openapi:generate": "turbo run openapi:generate",
1516
"openapi:validate": "turbo run openapi:validate",
1617
"test": "turbo run test"

0 commit comments

Comments
 (0)