lockwire 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lockwire/__init__.py +9 -0
- lockwire/__main__.py +9 -0
- lockwire/advice.py +119 -0
- lockwire/api.py +1216 -0
- lockwire/api_payload.py +985 -0
- lockwire/bench.py +182 -0
- lockwire/blame.py +100 -0
- lockwire/catalog.py +100 -0
- lockwire/catalog_seed.yaml +545 -0
- lockwire/checks.py +3483 -0
- lockwire/cli.py +1799 -0
- lockwire/cli_line.py +73 -0
- lockwire/constraints.py +313 -0
- lockwire/copy.py +302 -0
- lockwire/describe.py +682 -0
- lockwire/edit.py +2098 -0
- lockwire/emit_ts.py +150 -0
- lockwire/export_mhs.py +115 -0
- lockwire/factdiff.py +254 -0
- lockwire/forces.py +334 -0
- lockwire/gitref.py +188 -0
- lockwire/hw.py +388 -0
- lockwire/mcp_server.py +276 -0
- lockwire/mechanism.py +379 -0
- lockwire/mesh_dae.py +555 -0
- lockwire/mesh_simple.py +198 -0
- lockwire/page.py +1485 -0
- lockwire/plan.py +849 -0
- lockwire/plan_payload.py +151 -0
- lockwire/plugins.py +70 -0
- lockwire/report.py +848 -0
- lockwire/report_html.py +707 -0
- lockwire/report_json.py +168 -0
- lockwire/review_draft.py +315 -0
- lockwire/scan.py +732 -0
- lockwire/scene.py +535 -0
- lockwire/scene_import.py +309 -0
- lockwire/scene_urdf.py +750 -0
- lockwire/scene_view.py +376 -0
- lockwire/schema.py +3616 -0
- lockwire/sdf.py +240 -0
- lockwire/serve.py +1256 -0
- lockwire/start_operation.py +92 -0
- lockwire/statics.py +77 -0
- lockwire/units.py +115 -0
- lockwire/urdf.py +348 -0
- lockwire/vcs.py +402 -0
- lockwire/whatif.py +161 -0
- lockwire-0.2.0.dist-info/METADATA +192 -0
- lockwire-0.2.0.dist-info/RECORD +52 -0
- lockwire-0.2.0.dist-info/WHEEL +4 -0
- lockwire-0.2.0.dist-info/entry_points.txt +3 -0
lockwire/__init__.py
ADDED
lockwire/__main__.py
ADDED
lockwire/advice.py
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""The alternatives half of the advice sentence.
|
|
2
|
+
|
|
3
|
+
``check_budgets`` (``checks.py``) already knows a rail_power budget is over its
|
|
4
|
+
limit; this module answers the second half of the sentence — "what else could
|
|
5
|
+
carry it" — headroom on every OTHER rail_power budget, plus a projected
|
|
6
|
+
regulator suggestion. It computes nothing about rail membership itself:
|
|
7
|
+
Reuse means ``checks.power_rollup``'s own return values (rail totals, the
|
|
8
|
+
per-rail unknown-consumer sets) are passed in as plain data, never re-walked.
|
|
9
|
+
This module never imports ``checks`` — the call only ever goes the other way,
|
|
10
|
+
so there is no cycle.
|
|
11
|
+
|
|
12
|
+
Every number carries its ``kind`` (a catalog or projected
|
|
13
|
+
figure is shown only with its own visual mark and word, never in the same
|
|
14
|
+
style as a measured one): headroom is ``derived-by-<check>`` — the same
|
|
15
|
+
rollup ``check_budgets`` itself scores against; a suggested regulator rating
|
|
16
|
+
is ``projected``, a number this product is choosing, not measuring.
|
|
17
|
+
|
|
18
|
+
**Raising the over-budget rail's own declared capacity is never offered**
|
|
19
|
+
: that clears the finding by moving the limit rather than
|
|
20
|
+
the draw, which leaves a standing mark. Offering it as
|
|
21
|
+
advice would make the product recommend the exact thing that mark exists to flag.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from pydantic import BaseModel, ConfigDict, model_validator
|
|
27
|
+
|
|
28
|
+
from lockwire.schema import Contract
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class Alternative(BaseModel):
|
|
32
|
+
"""One remedy suggestion, its number, and the kind that number carries."""
|
|
33
|
+
|
|
34
|
+
model_config = ConfigDict(extra="forbid")
|
|
35
|
+
|
|
36
|
+
text: str
|
|
37
|
+
value: float
|
|
38
|
+
unit: str
|
|
39
|
+
kind: str # "derived-by-<check>" | "projected" | "none"
|
|
40
|
+
#: The word for a ``projected`` figure. Required when ``kind ==
|
|
41
|
+
#: "projected"`` — a projected figure reaching a door carries its mark and
|
|
42
|
+
#: its word, not a corrected sentence saying it is unenforced.
|
|
43
|
+
mark: str | None = None
|
|
44
|
+
|
|
45
|
+
@model_validator(mode="after")
|
|
46
|
+
def _carries_its_word(self) -> Alternative:
|
|
47
|
+
if self.kind == "projected" and not self.mark:
|
|
48
|
+
raise ValueError("a 'projected' number must carry its own word, e.g. mark='projected'")
|
|
49
|
+
return self
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def build_rail_alternatives(
|
|
53
|
+
contract: Contract,
|
|
54
|
+
*,
|
|
55
|
+
over_rail_id: str,
|
|
56
|
+
deficit_w: float,
|
|
57
|
+
rail_totals: dict[str, float],
|
|
58
|
+
rail_unknown: dict[str, set[str]],
|
|
59
|
+
check_name: str = "check_budgets",
|
|
60
|
+
) -> list[Alternative]:
|
|
61
|
+
"""Alternatives for a rail_power budget over its limit on ``over_rail_id``.
|
|
62
|
+
|
|
63
|
+
``rail_totals``/``rail_unknown`` must come from ``checks.power_rollup`` run
|
|
64
|
+
against the same contract and draw mode as the violation being explained —
|
|
65
|
+
the shared builder that every call site (and every mutation bite) goes
|
|
66
|
+
through, so a broken kind anywhere breaks every caller alike.
|
|
67
|
+
"""
|
|
68
|
+
alternatives: list[Alternative] = []
|
|
69
|
+
for budget in contract.budgets:
|
|
70
|
+
if budget.kind != "rail_power" or budget.rail in (None, over_rail_id):
|
|
71
|
+
continue
|
|
72
|
+
if rail_unknown.get(budget.rail):
|
|
73
|
+
# a rail with any consumer of unknown draw cannot be summed,
|
|
74
|
+
# so it cannot be claimed to have headroom either.
|
|
75
|
+
continue
|
|
76
|
+
used = rail_totals.get(budget.rail, 0.0)
|
|
77
|
+
headroom_w = budget.limit.base() - used
|
|
78
|
+
if headroom_w > 0.0:
|
|
79
|
+
alternatives.append(
|
|
80
|
+
Alternative(
|
|
81
|
+
text=(
|
|
82
|
+
f"move the device to rail {budget.rail!r}, which has "
|
|
83
|
+
f"{headroom_w:.2f} W free"
|
|
84
|
+
),
|
|
85
|
+
value=headroom_w,
|
|
86
|
+
unit="W",
|
|
87
|
+
kind=f"derived-by-{check_name}",
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
over_rail = contract.rail(over_rail_id)
|
|
92
|
+
source_rail_id = "battery"
|
|
93
|
+
if over_rail is not None and over_rail.upstream is not None:
|
|
94
|
+
source_rail_id = over_rail.upstream
|
|
95
|
+
rating_w = max(deficit_w, 0.0)
|
|
96
|
+
if rating_w > 0.0:
|
|
97
|
+
alternatives.append(
|
|
98
|
+
Alternative(
|
|
99
|
+
text=f"add a {rating_w:.2f} W regulator fed from rail {source_rail_id!r}",
|
|
100
|
+
value=rating_w,
|
|
101
|
+
unit="W",
|
|
102
|
+
kind="projected",
|
|
103
|
+
mark="projected",
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
if not alternatives:
|
|
108
|
+
alternatives.append(
|
|
109
|
+
Alternative(
|
|
110
|
+
text=(
|
|
111
|
+
f"no other rail has headroom for {over_rail_id!r} and no regulator "
|
|
112
|
+
"rating could be projected"
|
|
113
|
+
),
|
|
114
|
+
value=0.0,
|
|
115
|
+
unit="W",
|
|
116
|
+
kind="none",
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
return alternatives
|