perfact-api-pd-fastapi 1.17__tar.gz → 1.18__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 (32) hide show
  1. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/PKG-INFO +1 -1
  2. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/src/perfact/api/pd_fastapi/grafana.py +8 -2
  3. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/src/perfact_api_pd_fastapi.egg-info/PKG-INFO +1 -1
  4. perfact_api_pd_fastapi-1.18/src/perfact_api_pd_fastapi.egg-info/scm_version.json +8 -0
  5. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/tests/test_grafana.py +23 -0
  6. perfact_api_pd_fastapi-1.17/src/perfact_api_pd_fastapi.egg-info/scm_version.json +0 -8
  7. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/README.md +0 -0
  8. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/pyproject.toml +0 -0
  9. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/setup.cfg +0 -0
  10. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/src/perfact/api/pd_fastapi/__init__.py +0 -0
  11. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/src/perfact/api/pd_fastapi/kpi.py +0 -0
  12. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/src/perfact/api/pd_fastapi/pdunit.py +0 -0
  13. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/src/perfact/api/pd_fastapi/pdunitlch.py +0 -0
  14. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/src/perfact/api/pd_fastapi/performancedata.py +0 -0
  15. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/src/perfact/api/pd_fastapi/py.typed +0 -0
  16. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/src/perfact_api_pd_fastapi.egg-info/SOURCES.txt +0 -0
  17. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/src/perfact_api_pd_fastapi.egg-info/dependency_links.txt +0 -0
  18. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/src/perfact_api_pd_fastapi.egg-info/entry_points.txt +0 -0
  19. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/src/perfact_api_pd_fastapi.egg-info/requires.txt +0 -0
  20. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/src/perfact_api_pd_fastapi.egg-info/scm_file_list.json +0 -0
  21. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/src/perfact_api_pd_fastapi.egg-info/top_level.txt +0 -0
  22. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/tests/__init__.py +0 -0
  23. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/tests/conftest.py +0 -0
  24. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/tests/helpers.py +0 -0
  25. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/tests/locustfile.py +0 -0
  26. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/tests/test_init.py +0 -0
  27. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/tests/test_kpi.py +0 -0
  28. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/tests/test_lifecycle_lookup_wiring.py +0 -0
  29. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/tests/test_pdunit.py +0 -0
  30. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/tests/test_pdunitlch.py +0 -0
  31. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/tests/test_performance.py +0 -0
  32. {perfact_api_pd_fastapi-1.17 → perfact_api_pd_fastapi-1.18}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: perfact-api-pd-fastapi
3
- Version: 1.17
3
+ Version: 1.18
4
4
  Summary: PerFact API - SQLAlchemy+FastAPI pd apis package
5
5
  Author-email: Viktor Dick <viktor.dick@perfact.de>
6
6
  License-Expression: GPL-2.0-or-later
@@ -1,6 +1,6 @@
1
1
  from collections.abc import Callable
2
2
  from dataclasses import dataclass
3
- from typing import Any, Sequence
3
+ from typing import Any, Literal, Sequence
4
4
 
5
5
  from fastapi import HTTPException, status
6
6
  from perfact.api.base import AuthInfo, VisibilityPolicy, VisibilityPolicyRegistry
@@ -120,7 +120,11 @@ class ToolDowntimePayload(BaseModel):
120
120
  ``top_n`` is bounded to [1, _TOOL_DOWNTIME_MAX_TOP_N]. The id filters and
121
121
  ``sort`` are normalized through the same tolerant parsing the raw handler
122
122
  used, so an "All"/cleared template variable ('', [] or the unresolved
123
- ``$__all``) still means "no filter".
123
+ ``$__all``) still means "no filter" / the default.
124
+
125
+ ``sort_by`` picks the metric that ranks the top-N tools and orders the
126
+ output: ``"duration"`` (default, total downtime) or ``"quantity"``
127
+ (incident count). It is strict: any other value is rejected.
124
128
  """
125
129
 
126
130
  model_config = ConfigDict(populate_by_name=True)
@@ -134,6 +138,7 @@ class ToolDowntimePayload(BaseModel):
134
138
  pdtooltype_ids: list[int] = Field(default_factory=list, alias="pdtooltype")
135
139
  pdtool_ids: list[int] = Field(default_factory=list, alias="pdtool")
136
140
  sort: str = "desc"
141
+ sort_by: Literal["duration", "quantity"] = "duration"
137
142
 
138
143
  @field_validator("plant_tssm_ids", "pdtooltype_ids", "pdtool_ids", mode="before")
139
144
  @classmethod
@@ -194,6 +199,7 @@ def _tool_downtime_handler(
194
199
  pdtooltype_ids=payload.pdtooltype_ids,
195
200
  pdtool_ids=pdtool_ids,
196
201
  sort=payload.sort,
202
+ sort_by=payload.sort_by,
197
203
  )
198
204
  return tool_downtime_grafana_resp(rows, target.refId)
199
205
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: perfact-api-pd-fastapi
3
- Version: 1.17
3
+ Version: 1.18
4
4
  Summary: PerFact API - SQLAlchemy+FastAPI pd apis package
5
5
  Author-email: Viktor Dick <viktor.dick@perfact.de>
6
6
  License-Expression: GPL-2.0-or-later
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "1.18",
3
+ "distance": 0,
4
+ "node": "g9f0dd07206a5739cc8062f22dc81bb453502b68f",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-10-29"
8
+ }
@@ -242,6 +242,29 @@ def test_tool_downtime_handler_happy_path(monkeypatch: pytest.MonkeyPatch) -> No
242
242
  assert captured["pdtool_ids"] == [5]
243
243
 
244
244
 
245
+ @pytest.mark.parametrize(
246
+ "payload, expected",
247
+ [
248
+ ({"sort_by": "quantity"}, "quantity"),
249
+ ({"sort_by": "duration"}, "duration"),
250
+ ({}, "duration"), # absent -> default
251
+ ],
252
+ )
253
+ def test_tool_downtime_payload_sort_by(payload, expected) -> None:
254
+ assert grafana.ToolDowntimePayload.model_validate(payload).sort_by == expected
255
+
256
+
257
+ @pytest.mark.parametrize("value", ["bogus", "", "QUANTITY", None, 1])
258
+ def test_tool_downtime_handler_rejects_invalid_sort_by(value) -> None:
259
+ target = Target(target="pd.kpi.tool_downtime", payload={"sort_by": value})
260
+ query = QueryRequest.model_validate({})
261
+
262
+ with pytest.raises(HTTPException) as exc:
263
+ grafana._tool_downtime_handler(Mock(), _auth(), Mock(), target, query)
264
+
265
+ assert exc.value.status_code == 400
266
+
267
+
245
268
  def test_tool_downtime_handler_scopes_to_pdtool_visibility(
246
269
  monkeypatch: pytest.MonkeyPatch,
247
270
  ) -> None:
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "1.17",
3
- "distance": 0,
4
- "node": "g8b87d7e61610a913ae8a0c293f8f86e5524b5745",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-10-09"
8
- }