44 lines
3.1 KiB
Markdown
44 lines
3.1 KiB
Markdown
# Suggested Improvements to common/components.py
|
|
|
|
## Completed
|
|
|
|
### Caching on template rendering
|
|
- Added `functools.lru_cache` on `_render_cached()` wrapper around `render_to_string`
|
|
- Cache key: `(template_path, json.dumps(context, sort_keys=True))` — deterministic and unique
|
|
- `maxsize=4096` in production, disabled entirely in DEBUG mode (so template changes are reflected immediately)
|
|
- Only caches `template` path calls; `tag_name` calls are already nanosecond string ops
|
|
- Verified working: identical calls return identical output, different inputs produce separate cache entries
|
|
|
|
### Non-deterministic IDs
|
|
`randomid()` was replaced with `hashlib.sha1(content_hash.encode()).hexdigest()[:10]` for deterministic ID generation.
|
|
- `Popover()` passes content hash (`wrapped_content:popover_content:wrapped_classes`) so IDs are deterministic per unique content
|
|
- `games/templatetags/randomid.py` uses the same hash-based approach
|
|
- Fixes: caching (Popover output now cacheable), page consistency, thread safety
|
|
|
|
### Inconsistent return types
|
|
All component functions now return `SafeText` and are annotated accordingly. Redundant `mark_safe()` wrappers removed from `LinkedPurchase()` and `NameWithIcon()`.
|
|
|
|
### Fragile A() URL resolution
|
|
Replaced single `url` parameter with explicit `url_name` (URL pattern name resolved via `reverse()`) and `href` (literal path). Removed dead `Callable` type hint. `reverse()` now raises `NoReverseMatch` instead of silently falling back to literal text. Added mutual exclusion check — providing both parameters raises `ValueError`. Updated all 10 call sites across 6 view files and internal callers (`LinkedPurchase()`, `NameWithIcon()`).
|
|
|
|
### Toast XSS vulnerability
|
|
The vulnerable `Toast()` component (which used unsafe string escaping for
|
|
Alpine.js interpolation) had no callers and was deleted entirely. Toast display
|
|
is handled by the existing event-driven pipeline: middleware → `HX-Trigger`
|
|
headers → `show-toast` CustomEvent → Alpine store.
|
|
|
|
### Default mutable arguments
|
|
All functions with mutable defaults (`attributes` and `children`) changed from `= []` to `| None = None` with `or []` conversion in the body.
|
|
|
|
What was fixed: `attributes: list[HTMLAttribute] = []` and `children: list[HTMLTag] | HTMLTag = []` are a classic Python gotcha — the default is shared across all callers and could silently corrupt state if ever mutated in place. Changed 8 functions (`Component`, `Popover`, `A`, `Button`, `Div`, `Input`, `Form`, `Icon`) to use the `None` sentinel pattern, preventing future bugs and eliminating linter warnings.
|
|
|
|
## Incomplete
|
|
|
|
### No tests
|
|
Zero test coverage for the entire component system.
|
|
|
|
**Fix**: Add unit tests for each component function — basic rendering, edge cases,
|
|
and cache hit/miss verification.
|
|
|
|
**Done**: 96 unit tests covering all component functions (`Component`, `randomid`, `Popover`, `PopoverTruncated`, `A`, `Button`, `Div`, `Icon`, `Form`, `Input`, `NameWithIcon`, `LinkedPurchase`, `PurchasePrice`, `_render_cached`, `enable_cache`). Includes template rendering, deterministic ID generation, LRU cache behavior, HTML output validation, edge cases, error handling, and model-dependent integration tests.
|