You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.0 KiB
124 lines
3.0 KiB
# Naming Conventions
|
|
|
|
## Files
|
|
- **snake_case** for all Python files: `database.py`, `explorer_helpers.py`, `motion_cache.py`
|
|
- **PascalCase** NOT used for files
|
|
|
|
## Functions
|
|
- **snake_case**: `get_svd_vectors()`, `compute_party_coords()`, `build_scatter_trace()`
|
|
- Private helpers prefixed with `_`: `_get_window_data()`
|
|
|
|
## Classes
|
|
- **PascalCase**: `MotionDatabase`, `Config`
|
|
- **Dataclass pattern** for Config: `@dataclass` decorator with typed fields
|
|
|
|
## Variables
|
|
- **snake_case**: `party_map`, `mp_name`, `svd_vectors`, `party_centroids`
|
|
- **CONSTANT_SNAKE_CASE** for module-level constants: `PARTY_COLOURS`, `DEFAULT_WINDOW`
|
|
|
|
## Module-Level Exports
|
|
- **Singleton instance**: `db = MotionDatabase()` at module bottom (not class-level)
|
|
- **Config instance**: `config = Config(...)` at module bottom
|
|
- **Dicts**: `PARTY_COLOURS` exported from `config.py`
|
|
|
|
---
|
|
|
|
# Error Handling
|
|
|
|
## Known Patterns
|
|
1. **Bare except with pass** (ANTI-PATTERN - see anti-patterns.yaml)
|
|
```python
|
|
except:
|
|
pass # database.py:47
|
|
```
|
|
|
|
2. **Graceful degradation**: catch specific exceptions, fall back to default
|
|
```python
|
|
try:
|
|
result = compute_svd()
|
|
except ImportError:
|
|
result = DEFAULT_SVD
|
|
```
|
|
|
|
3. **Optional dependency fallbacks**:
|
|
```python
|
|
try:
|
|
import umap
|
|
use_umap = True
|
|
except ImportError:
|
|
use_umap = False
|
|
```
|
|
|
|
4. **Nested exception handling** (ANTI-PATTERN - see anti-patterns.yaml):
|
|
```python
|
|
try:
|
|
...
|
|
except Exception:
|
|
try:
|
|
...
|
|
except Exception:
|
|
pass
|
|
```
|
|
|
|
## Rules
|
|
- Never use bare `except:` — always specify exception type
|
|
- Never swallow exceptions silently — log or return a sensible default
|
|
- For optional deps, use `ImportError` or `ModuleNotFoundError` explicitly
|
|
- Avoid nested try/except blocks
|
|
|
|
---
|
|
|
|
# Code Organization
|
|
|
|
## Singleton Pattern
|
|
Each module owns one shared instance:
|
|
```python
|
|
# database.py
|
|
db = MotionDatabase()
|
|
|
|
# config.py
|
|
config = Config(...)
|
|
PARTY_COLOURS = {...}
|
|
```
|
|
|
|
## Pure Functions in Helpers
|
|
`explorer_helpers.py` contains only pure functions (no IO, no Streamlit calls):
|
|
```python
|
|
def compute_party_coords(svd_vectors, party_map):
|
|
"""Pure: no side effects, no imports from this module"""
|
|
...
|
|
|
|
def build_scatter_trace(df, color_col):
|
|
"""Pure: returns Plotly trace dict"""
|
|
...
|
|
```
|
|
|
|
## Cached Data Loaders
|
|
Use `@st.cache_data` for expensive data loading:
|
|
```python
|
|
@st.cache_data
|
|
def load_svd_vectors(window: str) -> pd.DataFrame:
|
|
return db.get_svd_vectors(window)
|
|
```
|
|
|
|
## Dataclass Config
|
|
```python
|
|
@dataclass
|
|
class Config:
|
|
db_path: str = "data/stemwijzer.duckdb"
|
|
default_window: str = "2023"
|
|
party_colours: dict = field(default_factory=lambda: PARTY_COLOURS)
|
|
```
|
|
|
|
---
|
|
|
|
# Imports
|
|
|
|
## Ordering (convention)
|
|
1. Standard library
|
|
2. Third-party (streamlit, ibis, plotly, sklearn, umap)
|
|
3. Local/relative imports
|
|
|
|
## Avoid
|
|
- Wildcard imports (`from module import *`)
|
|
- Circular imports (ensure dependency direction: helpers → database → config)
|
|
|