Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .cursor/skills/google-docstring-format/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
name: google-docstring-format
description: Write and fix Google-style docstrings that pass the project's check-docstrings pre-commit hook. Use when writing docstrings, fixing check-docstrings failures, ReferenceFormatError, InvalidTypeAnnotationError, or when docstring validation fails.
---

# Google Docstring Format (Project)

## Config (pyproject.toml)

```toml
[tool.docstring_checker]
paths = ["google_docstring_parser", "tools"]
require_param_types = true
check_references = true
check_type_consistency = true
exclude_files = ["test_malformed_docstrings.py"]
```

## Rules

### Args
- Every parameter **must** have a type: `param_name (type): description`
- Use `list[str]` not `list`; `dict[str, Any]` not `dict`. Bare collections fail validation.
- Types must match function annotations when `check_type_consistency` is true.

### Returns
- Use `Returns:` (plural), not `Return:` or `return:` or `returns:`
- Must have type: `Returns:\n dict[str, Any]: Description`
- Or just `None` if no return value.

### References
- **Single reference**: no leading dash
```
Reference:
Paper title: https://example.com/paper
```
- **Multiple references**: all must start with `-`
```
References:
- First paper: https://example.com/paper1
- Second paper: https://example.com/paper2
```
- Each reference needs non-empty `description` and `source` (colon-separated).

### Type validation
- `dict`, `list`, `set`, `tuple`, etc. require brackets: `list[str]`, `dict[str, int]`
- No unclosed parentheses in param types
- Brackets must be balanced and matched

## Fixing errors

| Error | Fix |
|-------|-----|
| `Parameter 'x' is missing a type` | Add `(type)` after param name |
| `Collection 'list' must include element types` | Use `list[str]` not `list` |
| `missing_dash` / `dash_in_single` | Single ref: no dash. Multiple refs: all start with `-` |
| `Invalid section name 'return:'` | Use `Returns:` |
| `Returns section is missing type annotation` | Add type before colon in Returns |

## Verify

```bash
pre-commit run check-docstrings --all-files
```
36 changes: 36 additions & 0 deletions .cursor/skills/pypi-release/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
name: pypi-release
description: Cut a PyPI release - bump version, build, upload. Use when releasing, publishing to PyPI, bumping version, or creating a new release.
---

# PyPI Release (Project)

## Workflow

1. **Bump version** in `pyproject.toml`:
```toml
version = "0.0.10" # was 0.0.9
```

2. **Commit and push**, create GitHub release (tag + publish)

3. **CI runs** `upload_to_pypi.yml` on `release: published`:
- Builds with `python -m build`
- Uploads with `twine upload dist/*`
- Uses `PYPI_API_TOKEN` secret

## Manual build/upload (if needed)

```bash
pip install build twine
python -m build
twine upload dist/*
```

Requires `TWINE_USERNAME=__token__` and `TWINE_PASSWORD` (PyPI token).

## CI job (upload_to_pypi.yml)

- Trigger: `release: types: [published]`
- Removes `tests` and `benchmark` before build
- Uses `secrets.PYPI_API_TOKEN`
48 changes: 48 additions & 0 deletions .cursor/skills/pytest-parametrize/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
name: pytest-parametrize
description: Write pytest tests using parametrize for similar cases, fixtures, and project test layout. Use when adding tests, writing test cases, parametrizing, or when asked to test new code.
---

# Pytest and Parametrize (Project)

## Test layout

- `tests/test_*.py` for top-level tests
- `tests/test_docstring_checker/` for checker-specific tests
- Use `pytest` and `@pytest.mark.parametrize`

## Parametrize pattern

```python
import pytest

@pytest.mark.parametrize(
"docstring,expected",
[
(
"""Description.

Args:
x (int): Param x
""",
{"Description": "Description.", "Args": [{"name": "x", "type": "int", "description": "Param x"}]},
),
# More cases...
],
)
def test_parse(docstring: str, expected: dict) -> None:
assert parse_google_docstring(docstring) == expected
```

## Guidelines

- Use parametrize when testing multiple similar inputs/outputs (same structure, different values)
- Keep each case as a `(input, expected)` tuple for clarity
- Use fixtures for shared setup (e.g. sample docstrings, config)
- Follow project style: type hints on test functions, no `# type: ignore` unless necessary

## Run tests

```bash
pytest
```
52 changes: 52 additions & 0 deletions .cursor/skills/python-pre-commit/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
name: python-pre-commit
description: Work with pre-commit hooks, fix pre-commit failures, add or update hooks. Use when pre-commit fails, adding pre-commit hooks, or debugging ruff/mypy/check-docstrings issues.
---

# Python Pre-commit (Project)

## Workflow

**Do not run ruff or flake8 directly.** Use:

```bash
pre-commit run --all-files
```

## Hooks (from .pre-commit-config.yaml)

| Hook | Config | Notes |
|------|--------|-------|
| ruff | pyproject.toml | Lint + format. `args: [--fix]` |
| ruff-format | pyproject.toml | Formatter |
| mypy | pyproject.toml | `files: ^(google_docstring_parser\|tests)/` |
| check-docstrings | local | `python -m tools.check_docstrings` |
| pyproject-fmt | - | Formats pyproject.toml |
| codespell | - | Spell check |
| pre-commit-hooks | - | AST, TOML, JSON, etc. |

## Lint rules

**Do not disable checks that force refactoring for better code** (e.g. C901 complexity). Fix the code instead.

## Config locations

- **Ruff**: `[tool.ruff]` in pyproject.toml (line-length 120, py310, pydocstyle google)
- **Mypy**: `[tool.mypy]` in pyproject.toml (strict: disallow_untyped_defs, etc.)
- **Docstrings**: `[tool.docstring_checker]` in pyproject.toml

## Fixing failures

1. Run `pre-commit run --all-files` to see all errors
2. Ruff: fix lint/format, often auto-fixable with `--fix`
3. Mypy: add types, fix annotations
4. check-docstrings: see google-docstring-format skill

## Add new hook

Edit `.pre-commit-config.yaml`, then:

```bash
pre-commit autoupdate # optional: update revs
pre-commit run --all-files
```
56 changes: 16 additions & 40 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,45 +12,25 @@ jobs:
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: [ubuntu-latest, windows-latest, macos-13]
python-version: ["3.10", "3.11", "3.12"]
include:
- operating-system: ubuntu-latest
path: ~/.cache/pip
- operating-system: windows-latest
path: ~\AppData\Local\pip\Cache
- operating-system: macos-13
path: ~/Library/Caches/pip
operating-system: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
fail-fast: true

steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
- name: Install uv and set Python version ${{ matrix.python-version }}
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: |
requirements-dev.txt

- name: Cache Python packages
uses: actions/cache@v4
with:
path: ${{ matrix.path }}
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements-dev.txt') }}
restore-keys: |
${{ runner.os }}-pip-${{ matrix.python-version }}-
${{ runner.os }}-pip-

- name: Install uv
run: pip install uv
activate-environment: true

- name: Install dependencies
run: |
uv pip install --system --upgrade pip wheel
uv pip install --system -r requirements-dev.txt
uv pip install --system .
uv pip install wheel
uv pip install .
uv pip install -r requirements-dev.txt

- name: Run PyTest with coverage
run: pytest
Expand All @@ -65,22 +45,18 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
- name: Install uv and set Python version ${{ matrix.python-version }}
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: |
requirements-dev.txt

- name: Install uv
run: pip install uv
activate-environment: true

- name: Install requirements
run: |
uv pip install --system --upgrade pip
uv pip install --system -r requirements-dev.txt
uv pip install --system .
uv pip install wheel
uv pip install .
uv pip install -r requirements-dev.txt

- name: Run checks
run: pre-commit run --all-files
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,5 @@ cython_debug/

# PyPI configuration file
.pypirc

uv.lock
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ Add a `[tool.docstring_checker]` section to your pyproject.toml:
paths = ["src", "tests"] # Directories or files to scan
require_param_types = true # Require parameter types in docstrings
check_references = true # Check references for proper format
check_type_consistency = true # Compare docstring types with annotations
exclude_files = ["conftest.py", "__init__.py"] # Files to exclude from checks
min_short_description_length = 10 # Minimum summary length; set to 0 to disable
verbose = false # Enable verbose output
```
Loading
Loading