qapu-cli 0.75.0__tar.gz → 0.76.0__tar.gz

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.
Files changed (46) hide show
  1. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/PKG-INFO +1 -1
  2. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/pyproject.toml +1 -1
  3. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/command_packages.py +12 -0
  4. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/main.py +85 -0
  5. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli.egg-info/PKG-INFO +1 -1
  6. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/README.md +0 -0
  7. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/__init__.py +0 -0
  8. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/client.py +0 -0
  9. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/__init__.py +0 -0
  10. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/app.py +0 -0
  11. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/app.tcss +0 -0
  12. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/data.py +0 -0
  13. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/rendering.py +0 -0
  14. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/screens/__init__.py +0 -0
  15. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/screens/catalog.py +0 -0
  16. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/screens/catalog_form.py +0 -0
  17. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/screens/catalog_picker.py +0 -0
  18. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/screens/confirm.py +0 -0
  19. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/screens/dashboard.py +0 -0
  20. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/screens/device_authorization.py +0 -0
  21. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/screens/device_edit.py +0 -0
  22. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/screens/device_list.py +0 -0
  23. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/screens/equipment_form.py +0 -0
  24. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/screens/group_detail.py +0 -0
  25. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/screens/group_form.py +0 -0
  26. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/screens/group_list.py +0 -0
  27. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/screens/infrastructure.py +0 -0
  28. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/widgets/__init__.py +0 -0
  29. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/tui/widgets/device_table.py +0 -0
  30. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli/visibility.py +0 -0
  31. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli.egg-info/SOURCES.txt +0 -0
  32. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli.egg-info/dependency_links.txt +0 -0
  33. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli.egg-info/entry_points.txt +0 -0
  34. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli.egg-info/requires.txt +0 -0
  35. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/qapu_cli.egg-info/top_level.txt +0 -0
  36. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/setup.cfg +0 -0
  37. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/tests/test_command_packages_complete.py +0 -0
  38. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/tests/test_login.py +0 -0
  39. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/tests/test_logout.py +0 -0
  40. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/tests/test_tui_authorization.py +0 -0
  41. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/tests/test_tui_catalog.py +0 -0
  42. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/tests/test_tui_device_edit.py +0 -0
  43. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/tests/test_tui_groups.py +0 -0
  44. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/tests/test_tui_infrastructure.py +0 -0
  45. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/tests/test_tui_smoke.py +0 -0
  46. {qapu_cli-0.75.0 → qapu_cli-0.76.0}/tests/test_visibility.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qapu-cli
3
- Version: 0.75.0
3
+ Version: 0.76.0
4
4
  Summary: CLI client for the Qapu API - built for the Hermes agent, but usable by anyone talking to api.ovoo.com.tr from outside the Swarm.
5
5
  Author: OVOO Technology
6
6
  Classifier: Programming Language :: Python :: 3
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "qapu-cli"
3
- version = "0.75.0"
3
+ version = "0.76.0"
4
4
  description = "CLI client for the Qapu API - built for the Hermes agent, but usable by anyone talking to api.ovoo.com.tr from outside the Swarm."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -63,6 +63,17 @@ COMMAND_REQUIRED_PACKAGES: dict[str, frozenset[str]] = {
63
63
  "calibration_get": frozenset({"calibration:read"}),
64
64
  "calibration_list": frozenset({"calibration:read"}),
65
65
  "calibration_update": frozenset({"calibration:write"}),
66
+ "calibration_assignment_add": frozenset({"calibration:write"}),
67
+ "calibration_assignment_delete": frozenset({"calibration:write"}),
68
+ "calibration_assignment_get": frozenset({"calibration:read"}),
69
+ "calibration_assignment_list": frozenset({"calibration:read"}),
70
+ "calibration_assignment_retire": frozenset({"calibration:write"}),
71
+ "calibration_assignment_update": frozenset({"calibration:write"}),
72
+ "calibration_profile_add": frozenset({"calibration:write"}),
73
+ "calibration_profile_delete": frozenset({"calibration:write"}),
74
+ "calibration_profile_get": frozenset({"calibration:read"}),
75
+ "calibration_profile_list": frozenset({"calibration:read"}),
76
+ "calibration_profile_update": frozenset({"calibration:write"}),
66
77
  "cinga_ai_list": frozenset({"mcp:read-only"}),
67
78
  "cinga_ai_log": frozenset({"observability:write"}),
68
79
  "crop_type_add": frozenset({"operations-catalog:write"}),
@@ -90,6 +101,7 @@ COMMAND_REQUIRED_PACKAGES: dict[str, frozenset[str]] = {
90
101
  "device_power": frozenset({"telemetry:read"}),
91
102
  "device_purge_history": frozenset({"devices:destructive"}),
92
103
  "device_reliability": frozenset({"telemetry:read"}),
104
+ "device_windows": frozenset({"telemetry:read"}),
93
105
  "device_trend": frozenset({"telemetry:read"}),
94
106
  "device_voltage": frozenset({"telemetry:read"}),
95
107
  "equipment_add": frozenset({"infrastructure:write"}),
@@ -1165,6 +1165,91 @@ def device_reliability(
1165
1165
  ]))
1166
1166
 
1167
1167
 
1168
+ _WINDOWS_PERIOD_TYPE_TO_CODE = {"day": 1, "week": 7, "month": 30}
1169
+ _WINDOWS_PERIOD_CODE_TO_LABEL = {1: "Günlük", 7: "Haftalık", 30: "Aylık"}
1170
+
1171
+
1172
+ @device_app.command("windows")
1173
+ def device_windows(
1174
+ device_id: str = typer.Argument(..., help="Device ID."),
1175
+ variable_id: Optional[str] = typer.Option(None, "--variable-id", help="Restrict to one variable (e.g. VRMS_A). Omit for every in-scope variable."),
1176
+ period: Optional[str] = typer.Option(None, "--period", help="day | week | month. Omit for all three."),
1177
+ days: Optional[int] = typer.Option(None, "--days", help="Window size in days, by window_start, ending now. Ignored if --start/--end are given."),
1178
+ start: Optional[str] = typer.Option(None, "--start", help="ISO date/datetime lower bound on window_start, inclusive. Takes priority over --days."),
1179
+ end: Optional[str] = typer.Option(None, "--end", help="ISO date/datetime upper bound on window_start, exclusive. Takes priority over --days."),
1180
+ limit: Optional[int] = typer.Option(None, "--limit", help="Cap the number of rows shown. Omit to page through everything interactively."),
1181
+ as_json: bool = typer.Option(False, "--json", help="Print raw JSON instead of a human-readable table."),
1182
+ ):
1183
+ """Pre-computed daily/weekly/monthly statistics for a device, voltage/current/power/energy only (GET /hermes/windows/{device_id}). Not real-time - see `qapu trend`/`qapu data` for live readings."""
1184
+
1185
+ # Translate --period's Friendly Name Into the Raw int the API Expects
1186
+ period_type: Optional[int] = None
1187
+ if period is not None:
1188
+ period_type = _WINDOWS_PERIOD_TYPE_TO_CODE.get(period.strip().lower())
1189
+ if period_type is None:
1190
+ console.print(f"[red]Geçersiz --period değeri: {period!r} (day, week veya month olmalı)[/red]")
1191
+ raise typer.Exit(code=1)
1192
+
1193
+ # Fetch the Rows
1194
+ params: dict[str, Any] = {}
1195
+ if variable_id:
1196
+ params["variable_id"] = variable_id
1197
+ if period_type is not None:
1198
+ params["period_type"] = period_type
1199
+ if start or end:
1200
+ if start:
1201
+ params["start"] = start
1202
+ if end:
1203
+ params["end"] = end
1204
+ elif days is not None:
1205
+ params["days"] = days
1206
+ rows: list[dict[str, Any]] = client.get(f"/hermes/windows/{device_id}", params=params)
1207
+
1208
+ # JSON Output - Nothing Further to Format
1209
+ if as_json:
1210
+ typer.echo(json.dumps(rows, indent=2))
1211
+ return
1212
+
1213
+ # No Rows - Say so Plainly
1214
+ if not rows:
1215
+ console.print(f"[yellow]{device_id} için kayıt bulunamadı.[/yellow]")
1216
+ return
1217
+
1218
+ # Build and Print the Table, Paginated Like Every Other Long List in
1219
+ # This CLI (device/variable/synthesis list) - a Device's own Window
1220
+ # History Can Easily Run Into the Hundreds of Rows Once Every Variable
1221
+ # and Period Type is Included.
1222
+ build_table = _simple_table_builder([
1223
+ ("DÖNEM", "period_type"),
1224
+ ("DEĞİŞKEN", "variable_id"),
1225
+ ("BAŞLANGIÇ", "window_start"),
1226
+ ("ORT", "mean"),
1227
+ ("MIN", "min"),
1228
+ ("MAKS", "max"),
1229
+ ("ÖRNEK", "sample_count"),
1230
+ ("TAMLIK", "completeness_ratio"),
1231
+ ])
1232
+
1233
+ # Pretty-Print Each Row's period_type/window_start/completeness_ratio
1234
+ # Before Handing off to the Generic Table Builder - Raw int Period
1235
+ # Codes and ISO Timestamps/Ratios Read Poorly Side by Side With Every
1236
+ # Other Column's Already-Human Values.
1237
+ display_rows = []
1238
+ for row in rows:
1239
+ display_row = dict(row)
1240
+ display_row["period_type"] = _WINDOWS_PERIOD_CODE_TO_LABEL.get(row.get("period_type"), row.get("period_type"))
1241
+ display_row["window_start"] = _format_time(row.get("window_start"))
1242
+ ratio = row.get("completeness_ratio")
1243
+ display_row["completeness_ratio"] = f"%{ratio * 100:.0f}" if ratio is not None else "-"
1244
+ for numeric_col in ("mean", "min", "max"):
1245
+ value = row.get(numeric_col)
1246
+ if isinstance(value, (int, float)):
1247
+ display_row[numeric_col] = round(value, 3)
1248
+ display_rows.append(display_row)
1249
+
1250
+ _print_paginated(display_rows, build_table, limit, "pencere")
1251
+
1252
+
1168
1253
  @device_app.command("purge-history")
1169
1254
  def device_purge_history(
1170
1255
  device_id: str = typer.Argument(..., help="Device ID."),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qapu-cli
3
- Version: 0.75.0
3
+ Version: 0.76.0
4
4
  Summary: CLI client for the Qapu API - built for the Hermes agent, but usable by anyone talking to api.ovoo.com.tr from outside the Swarm.
5
5
  Author: OVOO Technology
6
6
  Classifier: Programming Language :: Python :: 3
File without changes
File without changes
File without changes
File without changes
File without changes