perfact-api-pd-fastapi 1.16__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 (33) hide show
  1. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/PKG-INFO +2 -1
  2. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/pyproject.toml +1 -0
  3. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/src/perfact/api/pd_fastapi/grafana.py +8 -2
  4. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/src/perfact/api/pd_fastapi/pdunit.py +9 -4
  5. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/src/perfact/api/pd_fastapi/pdunitlch.py +34 -36
  6. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/src/perfact_api_pd_fastapi.egg-info/PKG-INFO +2 -1
  7. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/src/perfact_api_pd_fastapi.egg-info/SOURCES.txt +1 -0
  8. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/src/perfact_api_pd_fastapi.egg-info/requires.txt +1 -0
  9. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/src/perfact_api_pd_fastapi.egg-info/scm_file_list.json +1 -0
  10. perfact_api_pd_fastapi-1.18/src/perfact_api_pd_fastapi.egg-info/scm_version.json +8 -0
  11. perfact_api_pd_fastapi-1.18/tests/conftest.py +58 -0
  12. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/tests/test_grafana.py +23 -0
  13. perfact_api_pd_fastapi-1.18/tests/test_lifecycle_lookup_wiring.py +14 -0
  14. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/tests/test_pdunit.py +6 -1
  15. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/tests/test_pdunitlch.py +4 -0
  16. perfact_api_pd_fastapi-1.16/src/perfact_api_pd_fastapi.egg-info/scm_version.json +0 -8
  17. perfact_api_pd_fastapi-1.16/tests/conftest.py +0 -0
  18. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/README.md +0 -0
  19. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/setup.cfg +0 -0
  20. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/src/perfact/api/pd_fastapi/__init__.py +0 -0
  21. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/src/perfact/api/pd_fastapi/kpi.py +0 -0
  22. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/src/perfact/api/pd_fastapi/performancedata.py +0 -0
  23. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/src/perfact/api/pd_fastapi/py.typed +0 -0
  24. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/src/perfact_api_pd_fastapi.egg-info/dependency_links.txt +0 -0
  25. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/src/perfact_api_pd_fastapi.egg-info/entry_points.txt +0 -0
  26. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/src/perfact_api_pd_fastapi.egg-info/top_level.txt +0 -0
  27. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/tests/__init__.py +0 -0
  28. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/tests/helpers.py +0 -0
  29. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/tests/locustfile.py +0 -0
  30. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/tests/test_init.py +0 -0
  31. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/tests/test_kpi.py +0 -0
  32. {perfact_api_pd_fastapi-1.16 → perfact_api_pd_fastapi-1.18}/tests/test_performance.py +0 -0
  33. {perfact_api_pd_fastapi-1.16 → 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.16
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
@@ -14,6 +14,7 @@ Requires-Dist: perfact-api-pp
14
14
  Requires-Dist: perfact-api-pd
15
15
  Requires-Dist: perfact-api-main
16
16
  Requires-Dist: perfact-api-it
17
+ Requires-Dist: perfact-api-i18n-fastapi
17
18
 
18
19
  # PerFact API - pd - APIs
19
20
 
@@ -21,6 +21,7 @@ dependencies = [
21
21
  "perfact-api-pd",
22
22
  "perfact-api-main",
23
23
  "perfact-api-it",
24
+ "perfact-api-i18n-fastapi",
24
25
  ]
25
26
  dynamic = ["version"]
26
27
  requires-python = ">=3.10"
@@ -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
 
@@ -2,10 +2,11 @@ from typing import Optional, Sequence
2
2
 
3
3
  from fastapi import HTTPException
4
4
  from perfact.api.base.model import PydanticBase
5
+ from perfact.api.i18n_fastapi import Lang
5
6
  from perfact.api.main import Auth, DBSession, VisibilityRegistryDep, require_roles
6
7
  from perfact.api.main.dbsession import APIRouter
7
8
  from perfact.api.pd.model import PdUnit
8
- from sqlalchemy import select
9
+ from perfact.api.pd.services import list_pdunits
9
10
 
10
11
  routes = APIRouter()
11
12
 
@@ -26,8 +27,11 @@ class PdUnitGet(PydanticBase):
26
27
  )
27
28
  @require_roles("PdRead")
28
29
  def pdunit_get_all(
29
- session: DBSession, auth: Auth, visibility: VisibilityRegistryDep
30
- ) -> Sequence[PdUnit]:
30
+ session: DBSession,
31
+ auth: Auth,
32
+ visibility: VisibilityRegistryDep,
33
+ lang: Lang,
34
+ ) -> Sequence[PdUnitGet]:
31
35
  """
32
36
  returns all PdUnit which the current user is allowed to see.
33
37
  """
@@ -35,7 +39,8 @@ def pdunit_get_all(
35
39
  if auth is None:
36
40
  raise HTTPException(status_code=401, detail="Not authenticated")
37
41
 
38
- return session.execute(select(PdUnit).filter(policy.filter(auth))).scalars().all()
42
+ rows = list_pdunits(session, lang, policy.filter(auth))
43
+ return [PdUnitGet.model_validate(row) for row in rows]
39
44
 
40
45
 
41
46
  def mount(app: APIRouter):
@@ -3,17 +3,19 @@ from typing import Optional, Sequence
3
3
 
4
4
  from fastapi import HTTPException, Query
5
5
  from perfact.api.base.model import PydanticBase
6
+ from perfact.api.i18n_fastapi import Lang
6
7
  from perfact.api.main import Auth, DBSession, VisibilityRegistryDep, require_roles
7
8
  from perfact.api.main.dbsession import APIRouter
8
- from perfact.api.pd.model import (
9
- PdOrdLc,
10
- PdOrdLch,
11
- PdOrdLct,
12
- PdUnit,
13
- PdUnitLc,
14
- PdUnitLct,
9
+ from perfact.api.pd.model import PdOrdLch, PdUnit, PdUnitLct
10
+ from perfact.api.pd.services import (
11
+ find_pdunit,
12
+ get_unit_lch_history,
13
+ list_pdordlc,
14
+ list_pdordlch,
15
+ list_pdordlct,
16
+ list_pdunitlc,
17
+ list_pdunitlct,
15
18
  )
16
- from perfact.api.pd.services.pdunitlch import UnitLchHistoryEntry, get_unit_lch_history
17
19
  from pydantic import BaseModel, ConfigDict
18
20
  from sqlalchemy import select
19
21
 
@@ -72,8 +74,10 @@ class PdUnitLchEntryGet(BaseModel):
72
74
  response_model=Sequence[PdUnitLcGet],
73
75
  )
74
76
  @require_roles("PdRead")
75
- def pdunitlc_get_all(session: DBSession, auth: Auth) -> Sequence[PdUnitLc]:
76
- return session.execute(select(PdUnitLc)).scalars().all()
77
+ def pdunitlc_get_all(
78
+ session: DBSession, auth: Auth, lang: Lang
79
+ ) -> Sequence[PdUnitLcGet]:
80
+ return [PdUnitLcGet.model_validate(row) for row in list_pdunitlc(session, lang)]
77
81
 
78
82
 
79
83
  @routes.get(
@@ -84,7 +88,7 @@ def pdunitlc_get_all(session: DBSession, auth: Auth) -> Sequence[PdUnitLc]:
84
88
  )
85
89
  @require_roles("PdRead")
86
90
  def pdunitlct_get_all(session: DBSession, auth: Auth) -> Sequence[PdUnitLct]:
87
- return session.execute(select(PdUnitLct)).scalars().all()
91
+ return list_pdunitlct(session)
88
92
 
89
93
 
90
94
  @routes.get(
@@ -94,8 +98,8 @@ def pdunitlct_get_all(session: DBSession, auth: Auth) -> Sequence[PdUnitLct]:
94
98
  response_model=Sequence[PdOrdLcGet],
95
99
  )
96
100
  @require_roles("PdRead")
97
- def pdordlc_get_all(session: DBSession, auth: Auth) -> Sequence[PdOrdLc]:
98
- return session.execute(select(PdOrdLc)).scalars().all()
101
+ def pdordlc_get_all(session: DBSession, auth: Auth, lang: Lang) -> Sequence[PdOrdLcGet]:
102
+ return [PdOrdLcGet.model_validate(row) for row in list_pdordlc(session, lang)]
99
103
 
100
104
 
101
105
  @routes.get(
@@ -105,8 +109,10 @@ def pdordlc_get_all(session: DBSession, auth: Auth) -> Sequence[PdOrdLc]:
105
109
  response_model=Sequence[PdOrdLctGet],
106
110
  )
107
111
  @require_roles("PdRead")
108
- def pdordlct_get_all(session: DBSession, auth: Auth) -> Sequence[PdOrdLct]:
109
- return session.execute(select(PdOrdLct)).scalars().all()
112
+ def pdordlct_get_all(
113
+ session: DBSession, auth: Auth, lang: Lang
114
+ ) -> Sequence[PdOrdLctGet]:
115
+ return [PdOrdLctGet.model_validate(row) for row in list_pdordlct(session, lang)]
110
116
 
111
117
 
112
118
  @routes.get(
@@ -117,7 +123,7 @@ def pdordlct_get_all(session: DBSession, auth: Auth) -> Sequence[PdOrdLct]:
117
123
  )
118
124
  @require_roles("PdRead")
119
125
  def pdordlch_get_all(session: DBSession, auth: Auth) -> Sequence[PdOrdLch]:
120
- return session.execute(select(PdOrdLch)).scalars().all()
126
+ return list_pdordlch(session)
121
127
 
122
128
 
123
129
  @routes.get(
@@ -130,30 +136,21 @@ def pdordlch_get_all(session: DBSession, auth: Auth) -> Sequence[PdOrdLch]:
130
136
  def pdunitlch_get(
131
137
  session: DBSession,
132
138
  auth: Auth,
139
+ lang: Lang,
133
140
  visibility: VisibilityRegistryDep,
134
141
  pdunit_id: Optional[int] = None,
135
142
  pdunit_num: Optional[str] = None,
136
143
  sample_count: Optional[int] = Query(default=None, ge=1, le=MAX_SAMPLE_COUNT),
137
144
  starttime: Optional[datetime.datetime] = None,
138
145
  endtime: Optional[datetime.datetime] = None,
139
- ) -> list[UnitLchHistoryEntry]:
140
- # Resolve unit from id or num
141
- if pdunit_id is not None:
142
- unit = session.get(PdUnit, pdunit_id)
143
- elif pdunit_num is not None:
144
- unit = session.execute(
145
- select(PdUnit).where(PdUnit.num == pdunit_num)
146
- ).scalar_one_or_none()
147
- else:
148
- raise HTTPException(status_code=422, detail="Provide pdunit_id or pdunit_num")
149
-
150
- if unit is None:
151
- raise HTTPException(
152
- status_code=404,
153
- detail=f"PdUnit not found: {pdunit_id or pdunit_num!r}",
154
- )
146
+ ) -> list[PdUnitLchEntryGet]:
147
+ try:
148
+ unit = find_pdunit(session, pdunit_id=pdunit_id, pdunit_num=pdunit_num)
149
+ except ValueError as exc:
150
+ raise HTTPException(status_code=422, detail=str(exc)) from exc
151
+ except LookupError as exc:
152
+ raise HTTPException(status_code=404, detail=str(exc)) from exc
155
153
 
156
- # Visibility check applies regardless of which lookup path was used
157
154
  try:
158
155
  policy = visibility.get(PdUnit)
159
156
  except KeyError:
@@ -167,17 +164,18 @@ def pdunitlch_get(
167
164
  raise HTTPException(status_code=404)
168
165
 
169
166
  try:
170
- return get_unit_lch_history(
167
+ history = get_unit_lch_history(
171
168
  session,
172
169
  pdunit_id=unit.id,
173
170
  starttime=starttime,
174
171
  endtime=endtime,
175
172
  sample_count=sample_count,
173
+ lang=lang,
176
174
  )
177
175
  except ValueError as exc:
178
176
  raise HTTPException(status_code=422, detail=str(exc)) from exc
179
- except LookupError as exc:
180
- raise HTTPException(status_code=404, detail=str(exc)) from exc
177
+
178
+ return [PdUnitLchEntryGet.model_validate(entry) for entry in history]
181
179
 
182
180
 
183
181
  def mount(app: APIRouter) -> None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: perfact-api-pd-fastapi
3
- Version: 1.16
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
@@ -14,6 +14,7 @@ Requires-Dist: perfact-api-pp
14
14
  Requires-Dist: perfact-api-pd
15
15
  Requires-Dist: perfact-api-main
16
16
  Requires-Dist: perfact-api-it
17
+ Requires-Dist: perfact-api-i18n-fastapi
17
18
 
18
19
  # PerFact API - pd - APIs
19
20
 
@@ -23,6 +23,7 @@ tests/locustfile.py
23
23
  tests/test_grafana.py
24
24
  tests/test_init.py
25
25
  tests/test_kpi.py
26
+ tests/test_lifecycle_lookup_wiring.py
26
27
  tests/test_pdunit.py
27
28
  tests/test_pdunitlch.py
28
29
  tests/test_performance.py
@@ -3,3 +3,4 @@ perfact-api-pp
3
3
  perfact-api-pd
4
4
  perfact-api-main
5
5
  perfact-api-it
6
+ perfact-api-i18n-fastapi
@@ -16,6 +16,7 @@
16
16
  "tests/test_grafana.py",
17
17
  "tests/test_init.py",
18
18
  "tests/test_kpi.py",
19
+ "tests/test_lifecycle_lookup_wiring.py",
19
20
  "tests/test_pdunit.py",
20
21
  "tests/test_pdunitlch.py",
21
22
  "tests/test_performance.py",
@@ -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
+ }
@@ -0,0 +1,58 @@
1
+ import pytest
2
+ from perfact.api.base.model import Base
3
+ from perfact.api.i18n.model import I18nLang
4
+ from perfact.api.pd.model import (
5
+ PdOrdLc,
6
+ PdOrdLcI18n,
7
+ PdOrdLct,
8
+ PdOrdLctI18n,
9
+ PdPlant,
10
+ PdUnit,
11
+ PdUnitGroup,
12
+ PdUnitI18n,
13
+ PdUnitLc,
14
+ PdUnitLcI18n,
15
+ )
16
+ from pytest_postgresql import factories
17
+ from sqlalchemy import create_engine, text
18
+ from sqlalchemy.orm import Session
19
+
20
+ postgresql_proc = factories.postgresql_proc()
21
+ postgresql = factories.postgresql("postgresql_proc")
22
+
23
+ _TABLES = [
24
+ I18nLang.__table__,
25
+ PdUnitLc.__table__,
26
+ PdUnitLcI18n.__table__,
27
+ PdOrdLc.__table__,
28
+ PdOrdLcI18n.__table__,
29
+ PdOrdLct.__table__,
30
+ PdOrdLctI18n.__table__,
31
+ PdPlant.__table__,
32
+ PdUnitGroup.__table__,
33
+ PdUnit.__table__,
34
+ PdUnitI18n.__table__,
35
+ ]
36
+
37
+
38
+ @pytest.fixture
39
+ def db_engine(postgresql):
40
+ info = postgresql.info
41
+ url = f"postgresql+psycopg://{info.user}@{info.host}:{info.port}/{info.dbname}"
42
+ engine = create_engine(url)
43
+ with engine.begin() as conn:
44
+ conn.execute(
45
+ text(
46
+ "CREATE OR REPLACE FUNCTION db_username() RETURNS text "
47
+ "LANGUAGE SQL AS 'SELECT current_user'"
48
+ )
49
+ )
50
+ Base.metadata.create_all(engine, tables=_TABLES)
51
+ yield engine
52
+ engine.dispose()
53
+
54
+
55
+ @pytest.fixture
56
+ def db_session(db_engine):
57
+ with Session(db_engine) as session:
58
+ yield session
@@ -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:
@@ -0,0 +1,14 @@
1
+ from perfact.api.main.dbsession import APIRouter
2
+ from perfact.api.pd_fastapi import pdunitlch
3
+
4
+
5
+ def test_mount_includes_pdunitlc_pdordlc_pdordlct_routes() -> None:
6
+ """Mounting registers the lifecycle lookup routes."""
7
+ from .helpers import collect_paths
8
+
9
+ app_router = APIRouter()
10
+
11
+ pdunitlch.mount(app_router)
12
+
13
+ paths = collect_paths(app_router)
14
+ assert {"/pdunitlc", "/pdordlc", "/pdordlct"} <= paths
@@ -36,7 +36,12 @@ def test_pdunit_get_all_requires_authentication() -> None:
36
36
 
37
37
  with pytest.raises(HTTPException, match="Not authenticated") as exc_info:
38
38
  asyncio.run(
39
- pdunit.pdunit_get_all(session=session, auth=None, visibility=visibility) # type: ignore[arg-type]
39
+ pdunit.pdunit_get_all(
40
+ session=session,
41
+ auth=None, # type: ignore[arg-type]
42
+ visibility=visibility, # type: ignore[arg-type]
43
+ lang=None,
44
+ )
40
45
  )
41
46
 
42
47
  assert exc_info.value.status_code == 401
@@ -41,8 +41,10 @@ def test_pdunitlchentryget_exposes_pdordlc_name() -> None:
41
41
  entry = UnitLchHistoryEntry(
42
42
  createtime=datetime.datetime(2024, 1, 1, tzinfo=datetime.timezone.utc),
43
43
  pdunitlct_name="start",
44
+ pdunitlc_id=1,
44
45
  pdunitlc_name="running",
45
46
  pdord_num="ORD-1",
47
+ pdordlc_id=2,
46
48
  pdordlc_name="active",
47
49
  )
48
50
 
@@ -55,8 +57,10 @@ def test_pdunitlchentryget_pdordlc_name_none_when_no_active_operation() -> None:
55
57
  entry = UnitLchHistoryEntry(
56
58
  createtime=datetime.datetime(2024, 1, 1, tzinfo=datetime.timezone.utc),
57
59
  pdunitlct_name="start",
60
+ pdunitlc_id=1,
58
61
  pdunitlc_name="running",
59
62
  pdord_num=None,
63
+ pdordlc_id=None,
60
64
  pdordlc_name=None,
61
65
  )
62
66
 
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "1.16",
3
- "distance": 0,
4
- "node": "g8d3b01e2485ef0f77ee363eb02b4cbcad5c680ac",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-10-07"
8
- }
File without changes