Skip to content

Commit 5628408

Browse files
committed
Refactor: Migrate from black + pycodestyle to ruff
1 parent 49eeadd commit 5628408

7 files changed

Lines changed: 116 additions & 120 deletions

File tree

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Migrate from black + pycodestyle to ruff
2+
3+
## Context
4+
The project currently uses **black** (formatter) and **pycodestyle** (linter) as separate tools. Ruff is a faster, unified replacement that handles both formatting and linting. This migration consolidates two tools into one, with faster execution and a single configuration surface.
5+
6+
## Changes
7+
8+
### 1. Update `pyproject.toml` dependencies
9+
- **Remove** `black >= 22.8.0` and `pycodestyle >= 2.9.1` from `[dependency-groups] dev`
10+
- **Add** `ruff >= 0.9.0` to `[dependency-groups] dev`
11+
12+
### 2. Add ruff configuration to `pyproject.toml`
13+
Add the following sections:
14+
```toml
15+
[tool.ruff]
16+
line-length = 88 # match black's default
17+
target-version = "py310"
18+
19+
[tool.ruff.lint]
20+
select = ["E", "W", "F"] # pycodestyle errors/warnings + pyflakes
21+
```
22+
23+
### 3. Update CI workflow — `.github/workflows/lint.yml`
24+
Replace:
25+
```yaml
26+
- name: Check formatting
27+
run: uv run black --check bcb/ tests/
28+
```
29+
With:
30+
```yaml
31+
- name: Check formatting
32+
run: uv run ruff format --check bcb/ tests/
33+
- name: Lint
34+
run: uv run ruff check bcb/ tests/
35+
```
36+
37+
### 4. Update `CLAUDE.md`
38+
Replace the linting/formatting commands:
39+
```bash
40+
uv run ruff check bcb/ # lint with ruff
41+
uv run ruff format bcb/ # format with ruff
42+
```
43+
44+
### 5. Run `ruff format` on the codebase
45+
Run `uv run ruff format bcb/ tests/` to reformat with ruff (should produce no changes since ruff format is black-compatible by default, but verify).
46+
47+
### 6. Run `uv sync` to update lockfile
48+
After dependency changes, run `uv sync` to regenerate `uv.lock`.
49+
50+
## Files to modify
51+
- `pyproject.toml` — deps + ruff config
52+
- `.github/workflows/lint.yml` — CI steps
53+
- `CLAUDE.md` — documented commands
54+
55+
## Verification
56+
1. `uv run ruff format --check bcb/ tests/` — passes with no changes
57+
2. `uv run ruff check bcb/ tests/` — no lint errors
58+
3. `uv run mypy bcb/` — still passes (unchanged)
59+
4. `uv run pytest -m "not integration"` — all tests pass

.github/workflows/lint.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ jobs:
1919
run: uv sync --group dev
2020

2121
- name: Check formatting
22-
run: uv run black --check bcb/ tests/
22+
run: uv run ruff format --check bcb/ tests/
23+
24+
- name: Lint
25+
run: uv run ruff check bcb/ tests/
2326

2427
- name: Type check
2528
run: uv run mypy bcb/

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# Changelog
22

33
## [Unreleased]
4+
5+
## [0.3.5] - 2026-02-27
46
- Added `output="text"` parameter to `sgs.get()`, `currency.get()`, `EndpointQuery.collect()`, and `Endpoint.get()` — returns raw API response text (JSON for SGS and OData, CSV for currency) instead of a DataFrame; multi-code/symbol calls return `dict[key, str]`; default behavior unchanged
7+
- Migrated from Poetry to uv for package management (PEP 621 + hatchling build backend)
8+
- Replaced `black` and `pycodestyle` with `ruff` for linting and formatting
59

610
## [0.3.4] - 2026-02-25
711
- Replaced `requests` with `httpx` as the sole HTTP client across all modules

CLAUDE.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
88

99
## Python Environment
1010

11-
**This project uses uv exclusively.** All Python commands must be run via `uv run`. Never invoke `python`, `pytest`, `black`, or any other Python tool directly.
11+
**This project uses uv exclusively.** All Python commands must be run via `uv run`. Never invoke `python`, `pytest`, `ruff`, or any other Python tool directly.
1212

1313
```bash
1414
uv run python ...
1515
uv run pytest ...
16-
uv run black ...
16+
uv run ruff ...
1717
```
1818

1919
## Commands
@@ -36,8 +36,8 @@ Note: Many tests make live HTTP requests to BCB APIs. Tests marked with `@mark.f
3636

3737
### Linting / Formatting
3838
```bash
39-
uv run pycodestyle bcb/ # lint with pycodestyle
40-
uv run black bcb/ # format with black
39+
uv run ruff check bcb/ # lint with ruff
40+
uv run ruff format bcb/ # format with ruff
4141
```
4242

4343
### Docs

bcb/odata/framework.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from io import BytesIO
2-
import logging
32
from typing import Any, Optional, Union
43
from lxml import etree
54
import json
@@ -234,7 +233,7 @@ def __init__(self, **kwargs: Any) -> None:
234233
self.name: str = kwargs["Name"]
235234
self.parameters: list[ODataParameter] = kwargs["parameters"]
236235
self.return_type: str = kwargs["return_type"]
237-
self.fullname: str = f'{kwargs["namespace"]}.{self.name}'
236+
self.fullname: str = f"{kwargs['namespace']}.{self.name}"
238237

239238
def __repr__(self) -> str:
240239
return f"<Function {self.name}>"
@@ -422,7 +421,8 @@ def __init__(
422421
self.is_function = isinstance(entity, ODataFunctionImport)
423422
if self.is_function:
424423
self.function_parameters = {
425-
(p.name or ""): None for p in self.entity.function.parameters # type: ignore[union-attr]
424+
(p.name or ""): None
425+
for p in self.entity.function.parameters # type: ignore[union-attr]
426426
}
427427

428428
def odata_url(self) -> str:
@@ -513,7 +513,7 @@ def text(self) -> str:
513513
return res.text
514514

515515
def show(self) -> None:
516-
print(f"URL:")
516+
print("URL:")
517517
print(f" {self.odata_url()}")
518518
if self.is_function and len(self.function_parameters):
519519
print("Function Parameters:")
@@ -535,7 +535,8 @@ def show(self) -> None:
535535
print("Return:", names_str)
536536
else:
537537
names = [
538-
f"{p.name}<{p.ftype}>" for p in self.entity.entity.properties.values() # type: ignore[union-attr]
538+
f"{p.name}<{p.ftype}>"
539+
for p in self.entity.entity.properties.values() # type: ignore[union-attr]
539540
]
540541
names_str = ", ".join(names)
541542
print("Return:", names_str)

pyproject.toml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@ docs = [
2727
"pygments >= 2.7",
2828
]
2929
dev = [
30-
"pycodestyle >= 2.9.1",
30+
"ruff >= 0.9.0",
3131
"ipykernel >= 6.15.2",
32-
"black >= 22.8.0",
3332
"jupyter >= 1.1.1",
3433
"mypy >= 1.0.0",
3534
"pytest-cov >= 4.0.0",
@@ -60,3 +59,14 @@ fail_under = 70
6059
python_version = "3.10"
6160
strict = true
6261
ignore_missing_imports = true
62+
63+
[tool.ruff]
64+
line-length = 88
65+
target-version = "py310"
66+
67+
[tool.ruff.lint]
68+
select = ["E", "W", "F"]
69+
ignore = ["E501"]
70+
71+
[tool.ruff.lint.per-file-ignores]
72+
"__init__.py" = ["F401"]

0 commit comments

Comments
 (0)