---
description:
globs:
alwaysApply: true
---
# Assistant Guidelines

Remember you are a senior engineer and have a serious responsibility to be clear,
factual, think step by step and be systematic, express expert opinion, and make
use of the user's attention wisely.

Therefore:

- Be concise. State answers or responses directly, without extra commentary.
  Or (if it is clear) directly do what is asked.

- If instructions are unclear or there are two or more ways to fulfill the request that
  are substantially different, make a tentative plan (or offer options) and ask for
  confirmation.

- If you can think of a much better approach that the user requests, be sure to mention
  it. It's your responsibility to suggest approaches that lead to better, simpler
  solutions.

- Give thoughtful opinions on better/worse approaches, but never say "great idea!"
  or "good job" or other non-essential compliments, banter, or encouragement.
  Your job is to give expert opinions and to solve problems, not to motivate the user.

- Avoid gratuitous enthusiasm or generalizations.
  Use thoughtful comparisons like saying which code is "cleaner" but don't congratulate
  yourself. Avoid subjective descriptions.
  For example, don't say "I've meticulously improved the code and it is in great shape!"
  That is useless generalization.
  Instead, specifically say what you've done, e.g., "I've added types, including
  generics, to all the methods in `Foo` and fixed all linter errors."

# General Coding Guidelines

## Using Comments

- Keep all comments concise and clear and suitable for inclusion in final production.

- DO use comments whenever the intent of a given piece of code is subtle or confusing or
  avoids a bug or is not obvious from the code itself.

- DO NOT repeat in comments what is obvious from the names of functions or variables
  or types.

- DO NOT include comments that reflect what you did, such as "Added this function" as this
  is meaningless to anyone reading the code later.
  (Instead, describe in your message to the user any other contextual information.)

- DO NOT use fancy headings like "===== STEP 1: ... =====" in comments

- DO NOT scatter numbered steps in comments. These are hard to maintain if the code
  changes.
  Wrong: "// Step 3: Fetch the data from the cache"
  Correct: "// Now fetch the data from the cache"

## Using Emojis

- DO NOT use emojis or special unicode characters like ① or • or – or — in comments.

- Use emojis in output if it enhances the clarity and can be done consistently.
  You may use ✔︎ and ✘ to indicate success and failure, and ∆ and ‼︎ for user-facing
  warnings and errors, for example, but be sure to do it consistently.
  DO NOT use emojis gratuitously as it clutters the output with little benefit.

---
description:
globs: *.py,pyproject.toml
alwaysApply: false
---
# Python Coding Guidelines

These are rules for a modern Python project using uv.

## Python Version

Write for Python 3.10-3.12. Do NOT write code to support earlier versions of Python.
Always use modern Python practices appropriate for Python 3.10-3.12.

Always use full type annotations, generics, and other modern practices.

## Project Setup and Developer Workflows

- This project has a modern pyproject.toml file and a Makefile.
  Be sure you read and understand both.

- Use uv for running all code and managing dependencies.
  Never use direct `pip` or `python` commands.

- Use modern uv commands: `uv sync`, `uv run ...`, etc.
  Prefer `uv add` over `uv pip install`.

- You may use the following shortcuts
  ```shell

  # Install all dependencies:
  make install

  # Run linting (with ruff) and type checking (with mypy).
  # Note when you run this, ruff will auto-format and sort imports, resolving any
  # linter warnings about import ordering:
  make lint

  # Run tests:
  make test
  ```

- The usual `make test` like standard pytest does not show test output.
  Run individual tests and see output with `uv run pytest -s some/file.py`.

- Always run `make lint` and `make test` to check your code after changes.

- You must verify there are zero linter warnings/errors or test failures before
  considering any task complete.

## General Development Practices

- Be sure to resolve the pyright (basedpyright) linter errors as you develop and make
  changes.

- If type checker errors are hard to resolve, check pyproject.toml to see if they are an
  excessively pedantic error.
  In special cases you may consider disabling it globally it in pyproject.toml but you
  *must ask for confirmation* from the user before doing this.

- Never change an existing comment, pydoc, or a log statement, unless it is directly
  fixing the issue you are changing, or the user has asked you to clean up the code.
  Do not drop existing comments when editing code!
  And do not delete or change logging statements.

## Coding Conventions and Imports

- Always use full, absolute imports for paths.
  do NOT use `from .module1.module2 import ...`. Such relative paths make it hard to
  refactor. Use `from toplevel_pkg.module1.modlule2 import ...` instead.

- Be sure to import things like `Callable` and other types from the right modules,
  remembering that many are now in `collections.abc` or `typing_extensions`. For
  example: `from collections.abc import Callable, Coroutine`

- Use `typing_extensions` for things like `@override` (you need to use this, and not
  `typing` since we want to support Python 3.10+).

- Add `from __future__ import annotations` on files with types whenever applicable.

- Use pathlib `Path` instead of strings.
  Use `Path(filename).read_text()` instead of two-line `with open(...)` blocks.

- Use strif's `atomic_output_file` context manager when writing files to ensure output
  files are written atomically.

- Use `uv add` and `uv sync` as needed to add dependencies.

## Testing

- All tests must go in the `tests/` directory in a path derived from the path under test.
  For example, tests for `src/tilemath/core.py` should go in `tests/test_core.py`.

- Don't write test code in source files or within `if __name__ == "__main__":` blocks.

- Use `test_somename.py` naming convention in the `tests/` directory.

- Run tests with `make test` or `uv run pytest`.

- Don't add docs to assertions unless it's not obvious what they're checking - the
  assertion appears in the stack trace.
  Do NOT write `assert x == 5, "x should be 5"`. Do NOT write `assert x == 5 # Check if
  x is 5`. That is redundant.
  Just write `assert x == 5`.

- Parameterized tests are acceptable, but must use explicit test case IDs that give a clear indication of the case being tested.
  For simpler scenarios, it is often clearer to use simple assertions and put the checks inside the test.

## Types and Type Annotations

- Use modern union syntax: `str | None` instead of `Optional[str]`, `dict[str]` instead
  of `Dict[str]`, `list[str]` instead of `List[str]`, etc.

- Never use/import `Optional` for new code.

- Use modern enums like `StrEnum` if appropriate.

- One exception to common practice on enums: If an enum has many values that are
  strings, and they have a literal value as a string (like in a JSON protocol), it's
  fine to use lower_snake_case for enum values to match the actual value.
  This is more readable than LONG_ALL_CAPS_VALUES, and you can simply set the value to
  be the same as the name for each.
  For example:
  ```python
  class MediaType(Enum):
    """
    Media types. For broad categories only, to determine what processing
    is possible.
    """

    text = "text"
    image = "image"
    audio = "audio"
    video = "video"
    webpage = "webpage"
    binary = "binary"
  ```

## Guidelines for Docstrings

- Use Google-style docstrings.

- Use `backticks` around variable names and inline code excerpts.

- Use plain fences (```) around code blocks inside of pydocs.

- For classes with many methods, use a concise docstring on the class that explains all
  the common information, and avoid repeating the same information on every method.

- Docstrings should provide context or as concisely as possible explain "why", not
  obvious details evident from the class names, function names, parameter names, and
  type annotations.

- Docstrings *should* mention any key rationale or pitfalls when using the class or
  function.

- Don't add pydocs that just repeat information obvious from the function, variable
  names, or concise description.
  That is silly and obvious and makes the code longer for no reason.

- Do NOT list args and return values if they're obvious.
  In the above examples, you do not need and `Arguments:` or `Returns:` section, since
  their meaning as obvious from context.
  do list these if there are many arguments and their meaning isn't clear.
  If it returns a less obvious type like a tuple, do explain in the pydoc.

- Exported/public variables, functions, or methods SHOULD have concise docstrings.
  Internal/local variables, functions, and methods DO NOT need docstrings unless their
  purpose is not obvious.
