Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions .claude/rules/python/conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,32 @@ SUEWS-specific Python conventions. Complements ruff for standard linting.

## Critical Rules

1. **Config separation**: No config objects in low-level functions
1. **Python 3.9 compatibility**: Use `Optional[X]` not `X | None` for union types
```python
from typing import Optional, Union

# BAD: PEP 604 syntax requires Python 3.10+
def foo(x: str | None = None): ...
def bar(items: list[int] | None): ...

# GOOD: Works on Python 3.9+
def foo(x: Optional[str] = None): ...
def bar(items: Optional[list[int]]): ...
```
**Why**: PEP 604 union syntax (`X | Y`) requires Python 3.10+. Pydantic evaluates
type hints at runtime, so `from __future__ import annotations` is not a safe workaround.

2. **Config separation**: No config objects in low-level functions
```python
# BAD: def save_supy(df_output, config): ...
# GOOD: def save_supy(df_output, freq_s: int = 3600): ...
```

2. **Deep copy**: Use `copy.deepcopy()` for mutable state
3. **Deep copy**: Use `copy.deepcopy()` for mutable state

3. **Logging**: Use `logger_supy` not `print()`
4. **Logging**: Use `logger_supy` not `print()`

4. **pathlib**: Use `Path` not `os.path`
5. **pathlib**: Use `Path` not `os.path`

---

Expand Down
250 changes: 235 additions & 15 deletions docs/generate_datamodel_rst.py

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,14 @@ markers = [
line-length = 120
target-version = "py39"

[tool.ruff.lint]
# FA102: Catch PEP 604 union syntax (X | None) which requires Python 3.10+
# This prevents CI failures on Python 3.9 due to runtime TypeError
extend-select = ["FA102"]

# Note: FA102 auto-fix adds `from __future__ import annotations` which can break Pydantic
# Instead, manually use Optional[X] from typing module (see .claude/rules/python/conventions.md)

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
Loading
Loading