init
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
---
|
||||
name: python-style-preferences
|
||||
description: Apply the user's preferred Python engineering style for new modules, refactors, reviews, and project scaffolding. Use when working on Python CLIs, async services, libraries, typed data pipelines, or tensor-heavy code that should standardize on uv, anyio, click, full type annotations, basedpyright, jaxtyping, and beartype.
|
||||
---
|
||||
|
||||
# Python Style Preferences
|
||||
|
||||
## Overview
|
||||
|
||||
Follow these conventions whenever the task is primarily Python:
|
||||
|
||||
- Use `uv` for dependency management, virtualenv creation, locking, and command execution.
|
||||
- Prefer `anyio` over raw `asyncio` APIs.
|
||||
- Build CLIs with `click`.
|
||||
- Keep type annotations comprehensive enough for `basedpyright` to be useful by default.
|
||||
|
||||
## Working Style
|
||||
|
||||
1. Start with typed domain shapes.
|
||||
|
||||
- Prefer `TypedDict` for reusable mapping-shaped payloads.
|
||||
- Prefer `@dataclass(slots=True)` for reusable owned records and value objects.
|
||||
- Avoid reusable bare `dict[str, object]` structures; keep ad hoc dicts local and short-lived.
|
||||
|
||||
2. Keep entrypoints thin.
|
||||
|
||||
- Put parsing and CLI wiring in `click` commands.
|
||||
- Put business logic in typed functions and classes.
|
||||
- For async CLIs, use a synchronous `click` entrypoint that calls `anyio.run(...)`.
|
||||
|
||||
```python
|
||||
from pathlib import Path
|
||||
|
||||
import anyio
|
||||
import click
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument("config_path", type=click.Path(path_type=Path))
|
||||
def main(config_path: Path) -> None:
|
||||
anyio.run(run, config_path)
|
||||
|
||||
|
||||
async def run(config_path: Path) -> None:
|
||||
...
|
||||
```
|
||||
|
||||
3. Use `anyio` primitives consistently.
|
||||
|
||||
- Prefer `anyio.create_task_group()`, `anyio.fail_after()`, streams, and cancellation scopes.
|
||||
- Do not mix `asyncio.create_task`, `asyncio.gather`, or manual event-loop management into `anyio` code unless an external integration forces it.
|
||||
- When an `asyncio` boundary is unavoidable, isolate it and leave a short note.
|
||||
|
||||
4. Treat typing as enforcement, not decoration.
|
||||
|
||||
- Annotate public functions, methods, return values, and reusable internal helpers.
|
||||
- Run `basedpyright` as the default type-checking pass and keep new code clean.
|
||||
- Allow `cast(...)` only at trusted boundaries where runtime guarantees exist but inference cannot express them. Leave a short reason comment immediately above it.
|
||||
- Allow `# type: ignore[...]` only when it is narrow and justified. Leave a short reason comment immediately above it.
|
||||
|
||||
```python
|
||||
# basedpyright cannot infer the validated plugin registry value type here.
|
||||
runner = cast(Runner, registry[name])
|
||||
|
||||
# The vendor stub is wrong for this overload; runtime input is validated above.
|
||||
value = vendor_api.load(path) # type: ignore[call-overload]
|
||||
```
|
||||
|
||||
5. Use `jaxtyping` for arrays and tensors.
|
||||
|
||||
Short summary:
|
||||
|
||||
- Use `DType[ArrayType, "shape names"]`, for example `Float[np.ndarray, "batch channels"]`.
|
||||
- Reuse axis names to express shared dimensions across arguments and returns.
|
||||
- Use `...` for arbitrary extra axes and fixed integers for exact sizes.
|
||||
- Prefer reusable aliases for common tensor shapes.
|
||||
- Prefer concrete array types after normalization; use `ArrayLike` only at loose input boundaries.
|
||||
|
||||
See `references/jaxtyping-summary.md` for the fuller cheat sheet.
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
from beartype import beartype
|
||||
from jaxtyping import Float, jaxtyped
|
||||
|
||||
Batch = Float[np.ndarray, "batch channels"]
|
||||
|
||||
|
||||
@jaxtyped(typechecker=beartype)
|
||||
def normalize(x: Batch) -> Batch:
|
||||
...
|
||||
```
|
||||
|
||||
6. Use runtime type checking where it pays for itself.
|
||||
|
||||
- Prefer `beartype` together with `@jaxtyped(typechecker=beartype)` on stable boundaries, data adapters, numerical helpers, and test-targeted functions.
|
||||
- Avoid decorating the hottest inner loops unless the cost is clearly acceptable.
|
||||
- Avoid `from __future__ import annotations` or stringized annotations when runtime checking must inspect annotations directly.
|
||||
|
||||
## Verification
|
||||
|
||||
Use this order unless the project already has a stricter local workflow:
|
||||
|
||||
1. `uv sync --dev`
|
||||
2. `uv run basedpyright`
|
||||
3. `uv run pytest`
|
||||
4. `uv run python -m <package_or_module>` or a CLI smoke test when relevant
|
||||
|
||||
## Reference Files
|
||||
|
||||
- Read `references/jaxtyping-summary.md` when writing or reviewing array/tensor annotations.
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Python Style Preferences"
|
||||
short_description: "Typed Python with uv, anyio, click"
|
||||
default_prompt: "Apply the user's Python style preferences, typing rules, and validation workflow."
|
||||
@@ -0,0 +1,61 @@
|
||||
# Jaxtyping Summary
|
||||
|
||||
Use this reference when the task involves NumPy, JAX, PyTorch, TensorFlow, MLX, or array-like inputs that should carry shape and dtype information.
|
||||
|
||||
## Core syntax
|
||||
|
||||
- Use `DType[array_type, "shape"]`.
|
||||
- Examples:
|
||||
- `Float[np.ndarray, "batch channels"]`
|
||||
- `Int[np.ndarray, "persons"]`
|
||||
- `Shaped[ArrayLike, "batch time features"]`
|
||||
- `Float[Tensor, "... channels"]`
|
||||
|
||||
## Shape rules
|
||||
|
||||
- Reuse names to enforce equality across values: `"batch time"` with `"time features"`.
|
||||
- Use fixed integers for exact sizes: `"3 3"`.
|
||||
- Use `...` for zero or more anonymous axes.
|
||||
- Use `*name` for a named variadic axis.
|
||||
- Use `#name` when size `1` should also be accepted for broadcasting.
|
||||
- Use `_` or `name=...` only for documentation when runtime enforcement is not wanted.
|
||||
|
||||
## Array type guidance
|
||||
|
||||
- Prefer concrete normalized types in core logic:
|
||||
- `Float[np.ndarray, "..."]`
|
||||
- `Float[torch.Tensor, "..."]`
|
||||
- `Float[jax.Array, "..."]`
|
||||
- Use `Shaped[ArrayLike, "..."]` or another broader input type only at ingestion boundaries.
|
||||
- Create aliases for repeated shapes instead of rewriting them in every signature.
|
||||
|
||||
```python
|
||||
from jaxtyping import Float
|
||||
import numpy as np
|
||||
|
||||
FramePoints = Float[np.ndarray, "frames keypoints dims"]
|
||||
```
|
||||
|
||||
## Runtime checking
|
||||
|
||||
- Pair `jaxtyping` with `beartype` for runtime validation:
|
||||
|
||||
```python
|
||||
from beartype import beartype
|
||||
from jaxtyping import Float, jaxtyped
|
||||
import numpy as np
|
||||
|
||||
|
||||
@jaxtyped(typechecker=beartype)
|
||||
def center(x: Float[np.ndarray, "batch dims"]) -> Float[np.ndarray, "batch dims"]:
|
||||
return x - x.mean(axis=0)
|
||||
```
|
||||
|
||||
- Apply this at stable boundaries and in tests, not blindly on every hot loop.
|
||||
- Avoid `from __future__ import annotations` when relying on runtime checking.
|
||||
|
||||
## Practical defaults
|
||||
|
||||
- Prefer meaningful axis names like `batch`, `frames`, `persons`, `keypoints`, `dims`, `channels`.
|
||||
- Keep aliases near the module or domain where they are used.
|
||||
- If static typing and runtime truth diverge, validate at runtime first, then use a commented `cast(...)` at the narrow boundary.
|
||||
Reference in New Issue
Block a user