Skip to content

Commit 26423ac

Browse files
committed
Add Agents.md
1 parent aa66117 commit 26423ac

File tree

1 file changed

+243
-0
lines changed

1 file changed

+243
-0
lines changed

AGENTS.md

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
# Coding Agent Instructions
2+
3+
Guidance on how to navigate and modify this codebase.
4+
5+
## What this library does
6+
It is an async Python wrapper to interact with the Overkiz API, used by vendors and platforms like Somfy TaHoma and Atlantic CozyTouch.
7+
8+
## Python Version
9+
10+
Write for Python 3.10-3.13. Do NOT write code to support earlier versions of Python.
11+
Always use modern Python practices appropriate for Python 3.10-3.13.
12+
13+
Always use full type annotations, generics, and other modern practices.
14+
15+
## Project Setup and Developer Workflows
16+
17+
- Important: BE SURE you read and understand the project setup by reading the
18+
pyproject.toml file and the Makefile.
19+
20+
- ALWAYS use uv for running all code and managing dependencies.
21+
Never use direct `pip` or `python` commands.
22+
23+
- Use modern uv commands: `uv sync`, `uv run ...`, etc.
24+
Prefer `uv add` over `uv pip install`.
25+
26+
- You may use the following shortcuts
27+
```shell
28+
29+
# Install all dependencies:
30+
uv sync
31+
32+
# Run linting (with ruff), pre-commit checks and type checking (with mypy).
33+
# Note when you run this, ruff will auto-format and sort imports, resolving any
34+
# linter warnings about import ordering:
35+
uv run pre-commit run --all-files
36+
37+
# Run tests:
38+
uv run pytest
39+
```
40+
41+
- Run individual tests and see output with `uv run pytest -s some/file.py`.
42+
43+
- You must verify there are zero linter warnings/errors or test failures before considering any task complete.
44+
45+
## General Development Practices
46+
47+
- Be sure to resolve the mypy type checker errors as you develop and make
48+
changes.
49+
50+
- If type checker errors are hard to resolve, you may add a comment `# type: ignore`
51+
to disable mypy warnings or errors but ONLY if you know they are not a real problem
52+
and are difficult to fix.
53+
54+
- In special cases you may consider disabling it globally it in pyproject.toml but YOU
55+
MUST ASK FOR CONFIRMATION from the user before globally disabling lint or type checker
56+
rules.
57+
58+
- Never change an existing comment, pydoc, or a log statement, unless it is directly
59+
fixing the issue you are changing, or the user has asked you to clean up the code.
60+
Do not drop existing comments when editing code!
61+
And do not delete or change logging statements.
62+
63+
## Coding Conventions and Imports
64+
65+
- Always use full, absolute imports for paths.
66+
do NOT use `from .module1.module2 import ...`. Such relative paths make it hard to
67+
refactor. Use `from toplevel_pkg.module1.modlule2 import ...` instead.
68+
69+
- Be sure to import things like `Callable` and other types from the right modules,
70+
remembering that many are now in `collections.abc` or `typing_extensions`. For
71+
example: `from collections.abc import Callable, Coroutine`
72+
73+
- Use `typing_extensions` for things like `@override` (you need to use this, and not
74+
`typing` since we want to support Python 3.11).
75+
76+
- Add `from __future__ import annotations` on files with types whenever applicable.
77+
78+
- Use pathlib `Path` instead of strings.
79+
Use `Path(filename).read_text()` instead of two-line `with open(...)` blocks.
80+
81+
- Use strif’s `atomic_output_file` context manager when writing files to ensure output
82+
files are written atomically.
83+
84+
## Use Modern Python Practices
85+
86+
- ALWAYS use `@override` decorators to override methods from base classes.
87+
This is a modern Python practice and helps avoid bugs.
88+
89+
## Testing
90+
91+
- For longer tests put them in a file like `tests/test_somename.py` in the `tests/`
92+
directory (or `tests/module_name/test_somename.py` file for a submodule).
93+
94+
- For simple tests, prefer inline functions in the original code file below a `## Tests`
95+
comment. This keeps the tests easy to maintain and close to the code.
96+
Inline tests should NOT import pytest or pytest fixtures as we do not want runtime
97+
dependency on pytest.
98+
99+
- DO NOT write one-off test code in extra files that are throwaway.
100+
101+
- DO NOT put `if __name__ == "__main__":` just for quick testing.
102+
Instead use the inline function tests and run them with `uv run pytest`.
103+
104+
- You can run such individual tests with `uv run pytest -s src/.../path/to/test`
105+
106+
- Don’t add docs to assertions unless it’s not obvious what they’re checking - the
107+
assertion appears in the stack trace.
108+
Do NOT write `assert x == 5, "x should be 5"`. Do NOT write `assert x == 5 # Check if
109+
x is 5`. That is redundant.
110+
Just write `assert x == 5`.
111+
112+
- DO NOT write trivial or obvious tests that are evident directly from code, such as
113+
assertions that confirm the value of a constant setting.
114+
115+
- NEVER write `assert False`. If a test reaches an unexpected branch and must fail
116+
explicitly, `raise AssertionError("Some explanation")` instead.
117+
This is best typical best practice in Python since assertions can be removed with
118+
optimization.
119+
120+
- DO NOT use pytest fixtures like parameterized tests or expected exception decorators
121+
unless absolutely necessary in more complex tests.
122+
It is typically simpler to use simple assertions and put the checks inside the test.
123+
This is also preferable because then simple tests have no explicit pytest dependencies
124+
and can be placed in code anywhere.
125+
126+
- DO NOT write trivial tests that test something we know already works, like
127+
instantiating a Pydantic object.
128+
129+
```python
130+
class Link(BaseModel):
131+
url: str
132+
title: str = None
133+
134+
# DO NOT write tests like this. They are trivial and only create clutter!
135+
def test_link_model():
136+
link = Link(url="https://example.com", title="Example")
137+
assert link.url == "https://example.com"
138+
assert link.title == "Example"
139+
```
140+
141+
## Types and Type Annotations
142+
143+
- Use modern union syntax: `str | None` instead of `Optional[str]`, `dict[str]` instead
144+
of `Dict[str]`, `list[str]` instead of `List[str]`, etc.
145+
146+
- Never use/import `Optional` for new code.
147+
148+
- Use modern enums like `StrEnum` if appropriate.
149+
150+
## Guidelines for Comments
151+
152+
- Comments should be EXPLANATORY: Explain *WHY* something is done a certain way and not
153+
just *what* is done.
154+
155+
- Comments should be CONCISE: Remove all extraneous words.
156+
157+
- DO NOT use comments to state obvious things or repeat what is evident from the code.
158+
Here is an example of a comment that SHOULD BE REMOVED because it simply repeats the
159+
code, which is distracting and adds no value:
160+
```python
161+
if self.failed == 0:
162+
# All successful
163+
return "All tasks finished successfully"
164+
```
165+
166+
## Guidelines for Docstrings
167+
168+
- Here is an example of the correct style for docstrings:
169+
```python
170+
def check_if_url(
171+
text: UnresolvedLocator, only_schemes: list[str] | None = None
172+
) -> ParseResult | None:
173+
"""
174+
Convenience function to check if a string or Path is a URL and if so return
175+
the `urlparse.ParseResult`.
176+
177+
Also returns false for Paths, so that it's easy to use local paths and URLs
178+
(`Locator`s) interchangeably. Can provide `HTTP_ONLY` or `HTTP_OR_FILE` to
179+
restrict to only certain schemes.
180+
"""
181+
# Function body
182+
183+
def is_url(text: UnresolvedLocator, only_schemes: list[str] | None = None) -> bool:
184+
"""
185+
Check if a string is a URL. For convenience, also returns false for
186+
Paths, so that it's easy to use local paths and URLs interchangeably.
187+
"""
188+
return check_if_url(text, only_schemes) is not None
189+
```
190+
191+
- Use concise pydoc strings with triple quotes on their own lines.
192+
193+
- Use `backticks` around variable names and inline code excerpts.
194+
195+
- Use plain fences (```) around code blocks inside of pydocs.
196+
197+
- For classes with many methods, use a concise docstring on the class that explains all
198+
the common information, and avoid repeating the same information on every method.
199+
200+
- Docstrings should provide context or as concisely as possible explain “why”, not
201+
obvious details evident from the class names, function names, parameter names, and
202+
type annotations.
203+
204+
- Docstrings *should* mention any key rationale or pitfalls when using the class or
205+
function.
206+
207+
- Avoid obvious or repetitive docstrings.
208+
Do NOT add pydocs that just repeat in English facts that are obvious from the function
209+
name, variable name, or types.
210+
That is silly and obvious and makes the code longer for no reason.
211+
212+
- Do NOT list args and return values if they’re obvious.
213+
In the above examples, you do not need and `Arguments:` or `Returns:` section, since
214+
sections as it is obvious from context.
215+
do list these if there are many arguments and their meaning isn’t clear.
216+
If it returns a less obvious type like a tuple, do explain in the pydoc.
217+
218+
- Exported/public variables, functions, or methods SHOULD have concise docstrings.
219+
Internal/local variables, functions, and methods DO NOT need docstrings unless their
220+
purpose is not obvious.
221+
222+
## General Clean Coding Practices
223+
224+
- Avoid writing trivial wrapper functions.
225+
For example, when writing a class DO NOT blindly make delegation methods around public
226+
member variables. DO NOT write methods like this:
227+
```python
228+
def reassemble(self) -> str:
229+
"""Call the original reassemble method."""
230+
return self.paragraph.reassemble()
231+
```
232+
In general, the user can just call the enclosed objects methods, reducing code bloat.
233+
234+
- If a function does not use a parameter, but it should still be present, you can use `# type: ignore` in a comment to suppress the type checker warning.
235+
236+
## Guidelines for Backward Compatibility
237+
238+
- When changing code in a library or general function, if a change to an API or library
239+
will break backward compatibility, MENTION THIS to the user.
240+
241+
- DO NOT implement additional code for backward compatiblity (such as extra methods or
242+
variable aliases or comments about backward compatibility) UNLESS the user has
243+
confirmed that it is necessary.

0 commit comments

Comments
 (0)