|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +This file provides guidelines for AI coding agents (e.g., GitHub Copilot, Cursor, Codex) working in this repository. |
| 4 | + |
| 5 | +## Dependencies |
| 6 | + |
| 7 | +- Always use Poetry for dependency management (`poetry add <package>`) |
| 8 | +- Use Pydantic for data models |
| 9 | +- Use Pydantic-settings for environment variable configuration in a `settings.py` file |
| 10 | + |
| 11 | +## Testing Guidelines |
| 12 | + |
| 13 | +- Use pytest, not unittest |
| 14 | +- Use `pytest` monkeypatch and `pytest-mock` for mocking instead of `unittest.MagicMock` |
| 15 | +- Do not cheat! Never modify source code just to make a failing test pass. Fix real bugs in source code and fix incorrect assertions in tests |
| 16 | + |
| 17 | +## Make Targets |
| 18 | + |
| 19 | +Use `make` targets for all common workflows: lint, test, run locally, and deploy. Refer to `docs/README.md` for currently available targets. Add new targets to `Makefile` as needed. |
| 20 | + |
| 21 | +## Notes |
| 22 | + |
| 23 | +- Python 3.12+ required |
| 24 | +- Dependencies are managed via `pyproject.toml` and locked in `poetry.lock` |
| 25 | +- Do not edit `poetry.lock` directly; use `make update` to update dependencies |
| 26 | + |
| 27 | +## Coding Conventions |
| 28 | + |
| 29 | +### Field descriptions |
| 30 | + |
| 31 | +Every field in a Pydantic model or pydantic-settings class must be documented using `Field(description="...")`. This makes descriptions machine-readable and visible in generated JSON schemas. |
| 32 | + |
| 33 | +```python |
| 34 | +from uuid import uuid4 |
| 35 | +from pydantic import BaseModel, Field |
| 36 | + |
| 37 | +class Item(BaseModel, populate_by_name=True, alias_generator=to_camel): |
| 38 | + id: str = Field(description="Unique item identifier.", default_factory=lambda:str(uuid4())) |
| 39 | + name: str = Field(description="Human-readable item name.") |
| 40 | +``` |
| 41 | + |
| 42 | +### camelCase alias convention |
| 43 | + |
| 44 | +All `BaseModel` subclasses must be defined with `populate_by_name=True` and `alias_generator=to_camel` so that JSON payloads can use camelCase while Python attributes use snake_case. Always serialise with `model_dump(by_alias=True, exclude_none=True)` to produce camelCase JSON output and omit unset optional fields. |
| 45 | + |
| 46 | +```python |
| 47 | +from uuid import uuid4 |
| 48 | +from pydantic import BaseModel, Field |
| 49 | +from pydantic.alias_generators import to_camel |
| 50 | + |
| 51 | +class Item(BaseModel, populate_by_name=True, alias_generator=to_camel): |
| 52 | + item_id: str = Field(description="Unique item identifier.", default_factory=str(uuid4())) |
| 53 | + # Accepts {"itemId": "..."} from JSON; attribute is item.item_id |
| 54 | + # model_dump() → {"item_id": ...} |
| 55 | + # model_dump(by_alias=True, exclude_none=True) → {"itemId": ...} |
| 56 | +``` |
| 57 | + |
| 58 | +### No `model_config` class attribute |
| 59 | + |
| 60 | +Do not use `model_config = ConfigDict(...)` or `model_config = SettingsConfigDict(...)`. Pass configuration options as keyword arguments to the base class instead. |
| 61 | + |
| 62 | +```python |
| 63 | +# Good |
| 64 | +class Item(BaseModel, extra="allow", populate_by_name=True, alias_generator=to_camel): ... |
| 65 | +class Settings(BaseSettings, case_sensitive=False): ... |
| 66 | + |
| 67 | +# Bad |
| 68 | +class Item(BaseModel): |
| 69 | + model_config = ConfigDict(extra="allow") |
| 70 | +``` |
| 71 | + |
| 72 | +### Import style |
| 73 | + |
| 74 | +Do not add unnecessary imports like `from __future__ import annotations`. Always use explicit `from x import y` form: |
| 75 | + |
| 76 | +```python |
| 77 | +from json import dumps, loads |
| 78 | +from pytest import fixture, main, raises |
| 79 | +from aws_cdk.aws_lambda import Code, Function, Runtime |
| 80 | +``` |
| 81 | + |
| 82 | +### Test file main block |
| 83 | + |
| 84 | +Every test file must end with: |
| 85 | + |
| 86 | +```python |
| 87 | +if __name__ == "__main__": |
| 88 | + main() |
| 89 | +``` |
0 commit comments