2025-01-24 18:42:52 +00:00
|
|
|
# Development Guidelines
|
2025-01-03 15:26:25 +00:00
|
|
|
|
2025-01-24 18:42:52 +00:00
|
|
|
This document contains critical information about working with this codebase. Follow these guidelines precisely.
|
2025-01-03 15:26:25 +00:00
|
|
|
|
2025-01-24 18:42:52 +00:00
|
|
|
## Core Development Rules
|
2025-01-03 15:26:25 +00:00
|
|
|
|
2025-01-24 18:42:52 +00:00
|
|
|
1. Package Management
|
|
|
|
|
- ONLY use uv, NEVER pip
|
|
|
|
|
- Installation: `uv add package`
|
|
|
|
|
- Running tools: `uv run tool`
|
|
|
|
|
- Upgrading: `uv add --dev package --upgrade-package package`
|
|
|
|
|
- FORBIDDEN: `uv pip install`, `@latest` syntax
|
2025-01-03 15:26:25 +00:00
|
|
|
|
2025-01-24 18:42:52 +00:00
|
|
|
2. Code Quality
|
|
|
|
|
- Type hints required for all code
|
|
|
|
|
- Public APIs must have docstrings
|
|
|
|
|
- Functions must be focused and small
|
|
|
|
|
- Follow existing patterns exactly
|
2025-07-09 11:15:14 +01:00
|
|
|
- Line length: 120 chars maximum
|
2025-01-03 15:26:25 +00:00
|
|
|
|
2025-01-24 18:42:52 +00:00
|
|
|
3. Testing Requirements
|
2025-05-01 11:42:59 -07:00
|
|
|
- Framework: `uv run --frozen pytest`
|
2025-01-24 18:42:52 +00:00
|
|
|
- Async testing: use anyio, not asyncio
|
|
|
|
|
- Coverage: test edge cases and errors
|
|
|
|
|
- New features require tests
|
|
|
|
|
- Bug fixes require regression tests
|
2026-02-18 10:34:18 +00:00
|
|
|
- Avoid `anyio.sleep()` with a fixed duration to wait for async operations. Instead:
|
|
|
|
|
- Use `anyio.Event` — set it in the callback/handler, `await event.wait()` in the test
|
|
|
|
|
- For stream messages, use `await stream.receive()` instead of `sleep()` + `receive_nowait()`
|
|
|
|
|
- Exception: `sleep()` is appropriate when testing time-based features (e.g., timeouts)
|
|
|
|
|
- Wrap indefinite waits (`event.wait()`, `stream.receive()`) in `anyio.fail_after(5)` to prevent hangs
|
2025-01-03 15:26:25 +00:00
|
|
|
|
2025-01-24 14:20:42 +00:00
|
|
|
- For commits fixing bugs or adding features based on user reports add:
|
2025-07-10 16:43:49 +08:00
|
|
|
|
2025-01-24 14:20:42 +00:00
|
|
|
```bash
|
|
|
|
|
git commit --trailer "Reported-by:<name>"
|
|
|
|
|
```
|
2025-07-10 16:43:49 +08:00
|
|
|
|
2025-01-24 14:20:42 +00:00
|
|
|
Where `<name>` is the name of the user.
|
|
|
|
|
|
|
|
|
|
- For commits related to a Github issue, add
|
2025-07-10 16:43:49 +08:00
|
|
|
|
2025-01-24 14:20:42 +00:00
|
|
|
```bash
|
2025-01-24 16:59:58 +00:00
|
|
|
git commit --trailer "Github-Issue:#<number>"
|
2025-01-24 14:20:42 +00:00
|
|
|
```
|
2025-07-10 16:43:49 +08:00
|
|
|
|
2025-01-24 14:20:42 +00:00
|
|
|
- NEVER ever mention a `co-authored-by` or similar aspects. In particular, never
|
|
|
|
|
mention the tool used to create the commit message or PR.
|
|
|
|
|
|
|
|
|
|
## Pull Requests
|
|
|
|
|
|
|
|
|
|
- Create a detailed message of what changed. Focus on the high level description of
|
|
|
|
|
the problem it tries to solve, and how it is solved. Don't go into the specifics of the
|
|
|
|
|
code unless it adds clarity.
|
|
|
|
|
|
|
|
|
|
- NEVER ever mention a `co-authored-by` or similar aspects. In particular, never
|
|
|
|
|
mention the tool used to create the commit message or PR.
|
|
|
|
|
|
|
|
|
|
## Python Tools
|
2025-01-03 15:26:25 +00:00
|
|
|
|
2025-01-24 18:42:52 +00:00
|
|
|
## Code Formatting
|
2025-01-03 15:26:25 +00:00
|
|
|
|
2025-01-24 18:42:52 +00:00
|
|
|
1. Ruff
|
2025-05-01 11:42:59 -07:00
|
|
|
- Format: `uv run --frozen ruff format .`
|
|
|
|
|
- Check: `uv run --frozen ruff check .`
|
|
|
|
|
- Fix: `uv run --frozen ruff check . --fix`
|
2025-01-24 18:42:52 +00:00
|
|
|
- Critical issues:
|
|
|
|
|
- Line length (88 chars)
|
|
|
|
|
- Import sorting (I001)
|
|
|
|
|
- Unused imports
|
|
|
|
|
- Line wrapping:
|
|
|
|
|
- Strings: use parentheses
|
|
|
|
|
- Function calls: multi-line with proper indent
|
|
|
|
|
- Imports: split into multiple lines
|
2025-01-03 15:26:25 +00:00
|
|
|
|
2025-01-24 18:42:52 +00:00
|
|
|
2. Type Checking
|
2025-05-01 11:42:59 -07:00
|
|
|
- Tool: `uv run --frozen pyright`
|
2025-01-24 18:42:52 +00:00
|
|
|
- Requirements:
|
|
|
|
|
- Explicit None checks for Optional
|
|
|
|
|
- Type narrowing for strings
|
|
|
|
|
- Version warnings can be ignored if checks pass
|
2025-01-03 15:57:56 +00:00
|
|
|
|
2025-01-24 18:42:52 +00:00
|
|
|
3. Pre-commit
|
|
|
|
|
- Config: `.pre-commit-config.yaml`
|
|
|
|
|
- Runs: on git commit
|
|
|
|
|
- Tools: Prettier (YAML/JSON), Ruff (Python)
|
|
|
|
|
- Ruff updates:
|
|
|
|
|
- Check PyPI versions
|
|
|
|
|
- Update config rev
|
|
|
|
|
- Commit config first
|
2025-01-03 15:57:56 +00:00
|
|
|
|
2025-01-24 18:42:52 +00:00
|
|
|
## Error Resolution
|
2025-01-03 15:26:25 +00:00
|
|
|
|
2025-01-24 18:42:52 +00:00
|
|
|
1. CI Failures
|
|
|
|
|
- Fix order:
|
|
|
|
|
1. Formatting
|
|
|
|
|
2. Type errors
|
|
|
|
|
3. Linting
|
|
|
|
|
- Type errors:
|
|
|
|
|
- Get full line context
|
|
|
|
|
- Check Optional types
|
|
|
|
|
- Add type narrowing
|
|
|
|
|
- Verify function signatures
|
|
|
|
|
|
|
|
|
|
2. Common Issues
|
|
|
|
|
- Line length:
|
|
|
|
|
- Break strings with parentheses
|
|
|
|
|
- Multi-line function calls
|
|
|
|
|
- Split imports
|
|
|
|
|
- Types:
|
|
|
|
|
- Add None checks
|
|
|
|
|
- Narrow string types
|
|
|
|
|
- Match existing patterns
|
2025-05-01 11:42:59 -07:00
|
|
|
- Pytest:
|
|
|
|
|
- If the tests aren't finding the anyio pytest mark, try adding PYTEST_DISABLE_PLUGIN_AUTOLOAD=""
|
|
|
|
|
to the start of the pytest run command eg:
|
|
|
|
|
`PYTEST_DISABLE_PLUGIN_AUTOLOAD="" uv run --frozen pytest`
|
2025-01-24 18:42:52 +00:00
|
|
|
|
|
|
|
|
3. Best Practices
|
|
|
|
|
- Check git status before commits
|
|
|
|
|
- Run formatters before type checks
|
|
|
|
|
- Keep changes minimal
|
|
|
|
|
- Follow existing patterns
|
|
|
|
|
- Document public APIs
|
2025-01-24 14:20:42 +00:00
|
|
|
- Test thoroughly
|
2025-07-09 11:15:14 +01:00
|
|
|
|
|
|
|
|
## Exception Handling
|
|
|
|
|
|
|
|
|
|
- **Always use `logger.exception()` instead of `logger.error()` when catching exceptions**
|
|
|
|
|
- Don't include the exception in the message: `logger.exception("Failed")` not `logger.exception(f"Failed: {e}")`
|
|
|
|
|
- **Catch specific exceptions** where possible:
|
|
|
|
|
- File ops: `except (OSError, PermissionError):`
|
|
|
|
|
- JSON: `except json.JSONDecodeError:`
|
|
|
|
|
- Network: `except (ConnectionError, TimeoutError):`
|
|
|
|
|
- **Only catch `Exception` for**:
|
|
|
|
|
- Top-level handlers that must not crash
|
|
|
|
|
- Cleanup blocks (log at debug level)
|