UX-08 2d review: action log reachable in status JSON, engaged peak row pinned, imported keys expanded
- status_payload() also returns the action log as `events`. The page does not render it. Some entries (a dropped inverter's reason, the peak guard's projection, unplaced watts) are written nowhere else, and DOCS still points installers at the action log. - test_peakguard pins the engaged row's ordered pair (the battery's share, then the limit). - test_messages expands setting keys named by constants imported from another app module, so the shown-text 30-word scan counts them. - p1.py: 'A meter message could not be read'. DOCS glossary: control board in plain words, with the hardware in an installer note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -402,6 +402,18 @@ def strings_in(node, expand=False):
|
||||
yield from strings_in(child, expand)
|
||||
|
||||
|
||||
def _module_constants(tree):
|
||||
"""Module-level `NAME = "text"` assignments."""
|
||||
return {t.id: n.value.value for n in tree.body
|
||||
if isinstance(n, ast.Assign) and isinstance(n.value, ast.Constant)
|
||||
and isinstance(n.value.value, str)
|
||||
for t in n.targets if isinstance(t, ast.Name)}
|
||||
|
||||
|
||||
_MODCONST = {f.stem: _module_constants(ast.parse(f.read_text(encoding="utf-8")))
|
||||
for f in sorted(APP.glob("*.py"))}
|
||||
|
||||
|
||||
def collect():
|
||||
"""(kind, where, text) for every user-facing literal of a ratcheted kind."""
|
||||
out = []
|
||||
@@ -409,12 +421,16 @@ def collect():
|
||||
if f.name == "messages.py":
|
||||
continue
|
||||
tree = ast.parse(f.read_text(encoding="utf-8"))
|
||||
# The file's own constants, and those it imports from another app
|
||||
# module (`from .validate import TAXES_PROFILE_OPTION`), so a key
|
||||
# named by a constant from elsewhere is expanded too.
|
||||
CONSTANTS.clear()
|
||||
CONSTANTS.update({t.id: n.value.value for n in tree.body
|
||||
if isinstance(n, ast.Assign)
|
||||
and isinstance(n.value, ast.Constant)
|
||||
and isinstance(n.value.value, str)
|
||||
for t in n.targets if isinstance(t, ast.Name)})
|
||||
CONSTANTS.update(_module_constants(tree))
|
||||
for n in tree.body:
|
||||
if isinstance(n, ast.ImportFrom) and n.level == 1 and n.module:
|
||||
theirs = _MODCONST.get(n.module, {})
|
||||
CONSTANTS.update({a.asname or a.name: theirs[a.name]
|
||||
for a in n.names if a.name in theirs})
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Dict):
|
||||
for k, v in zip(node.keys, node.values):
|
||||
|
||||
Reference in New Issue
Block a user