Skip to content

Commit cc93e1d

Browse files
snopokeclaude
andcommitted
add CLAUDE.md and fix tasks.py to use tomlkit
tasks.py still called `poetry version` after the move to uv; replace with a small tomlkit-based bumper (tomlkit is already a dependency). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent be9fda1 commit cc93e1d

2 files changed

Lines changed: 89 additions & 11 deletions

File tree

CLAUDE.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Task Badger Python SDK
2+
3+
Official Python client for [Task Badger](https://taskbadger.net/). Public package: `taskbadger` on PyPI.
4+
5+
## Commands
6+
7+
```bash
8+
uv sync --frozen # Install deps (incl. dev + cli extras via dependency-groups)
9+
uv run pytest # Run unit tests (integration_tests/ is excluded by default)
10+
uv run pytest integration_tests -vs # Run integration tests (needs Redis + TASKBADGER_API_KEY)
11+
uv run ruff check . --fix # Lint
12+
uv run ruff format . # Format
13+
uv build # Build sdist + wheel
14+
```
15+
16+
Pre-commit runs ruff-check + ruff-format; install with `uv run pre-commit install`.
17+
18+
## Architecture
19+
20+
- `taskbadger/` — SDK source
21+
- `sdk.py`, `mug.py`, `safe_sdk.py` — public API surface (re-exported from `__init__.py`)
22+
- `decorators.py``@track` decorator
23+
- `systems/`, `celery.py` — Celery integration (optional extra)
24+
- `cli/`, `cli_main.py` — Typer-based CLI (optional `[cli]` extra)
25+
- `internal/`**generated** by `openapi-python-client`; do not hand-edit
26+
- `tests/` — unit tests (pytest, pytest-httpx)
27+
- `integration_tests/` — hits real Task Badger API; excluded from default pytest run
28+
- `taskbadger.yaml` — OpenAPI schema used to regenerate `internal/`
29+
30+
## Regenerating the API client
31+
32+
```bash
33+
uv run invoke update-api # Pull latest schema + regenerate
34+
uv run invoke update-api --local # Regenerate from existing taskbadger.yaml
35+
```
36+
37+
The `update-api` invoke task curls `localhost:8000/api/schema.json` by default — pass `--local` if you don't have the API server running.
38+
39+
## Code Style
40+
41+
- Ruff: line-length 120, target Python 3.10, rules `E F I UP DJ PT`.
42+
- Supports Python 3.10–3.14 — don't use 3.11+ syntax (e.g. `Self`, `LiteralString`).
43+
- Celery and CLI deps are optional; guard imports inside `taskbadger/celery.py`, `taskbadger/systems/celery.py`, `taskbadger/cli/`.
44+
- `taskbadger/internal/*` is generator output — lint is best-effort, don't reformat manually.
45+
46+
## Releasing
47+
48+
```bash
49+
uv run invoke tag-release # Bumps version in pyproject.toml, tags, pushes — triggers release.yml
50+
```
51+
52+
GitHub Actions then drafts a release; publishing the release triggers `publish.yml` → PyPI.
53+
54+
## Gotchas
55+
56+
- `pytest` skips `integration_tests/` via `norecursedirs` — name them explicitly to run.
57+
- Integration tests need `TASKBADGER_ORG`, `TASKBADGER_PROJECT`, `TASKBADGER_API_KEY` env vars and a running Redis.
58+
- Imports of `celery`, `typer`, `rich` must stay optional — only the core httpx/attrs deps are guaranteed.

tasks.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1+
from pathlib import Path
2+
3+
import tomlkit
14
from invoke import Context, task
25

6+
PYPROJECT = Path(__file__).parent / "pyproject.toml"
7+
38

49
@task
510
def tag_release(c: Context):
6-
version = _get_version(c)
7-
bump_key = input("Current version: {version}. Bump? [1: major, 2: minor, 3: patch / n]")
11+
version = _get_version()
12+
bump_key = input(f"Current version: {version}. Bump? [1: major, 2: minor, 3: patch / n]")
813
if bump_key in ("1", "2", "3"):
9-
bump = {"1": "major", "2": "minor", "3": "patch"}.get(bump_key)
10-
11-
c.run(f"poetry version {bump}")
12-
version = _get_version(c)
14+
bump = {"1": "major", "2": "minor", "3": "patch"}[bump_key]
15+
version = _bump_version(bump)
1316
c.run("git add pyproject.toml")
1417
c.run(f"git commit -m 'Bump version to {version}'")
1518

@@ -21,11 +24,6 @@ def tag_release(c: Context):
2124
print("Check https://github.com/taskbadger/taskbadger-python/releases and publish the release.")
2225

2326

24-
def _get_version(c):
25-
version = c.run("poetry version -s", hide="out").stdout.strip()
26-
return version
27-
28-
2927
@task
3028
def update_api(c, local=False):
3129
if not local:
@@ -35,3 +33,25 @@ def update_api(c, local=False):
3533
"--config generator_config.yml --overwrite "
3634
"--output-path taskbadger/internal"
3735
)
36+
37+
38+
def _get_version() -> str:
39+
doc = tomlkit.parse(PYPROJECT.read_text())
40+
return doc["project"]["version"]
41+
42+
43+
def _bump_version(part: str) -> str:
44+
doc = tomlkit.parse(PYPROJECT.read_text())
45+
major, minor, patch = (int(x) for x in doc["project"]["version"].split("."))
46+
if part == "major":
47+
major, minor, patch = major + 1, 0, 0
48+
elif part == "minor":
49+
minor, patch = minor + 1, 0
50+
elif part == "patch":
51+
patch += 1
52+
else:
53+
raise ValueError(f"unknown bump part: {part}")
54+
new = f"{major}.{minor}.{patch}"
55+
doc["project"]["version"] = new
56+
PYPROJECT.write_text(tomlkit.dumps(doc))
57+
return new

0 commit comments

Comments
 (0)