Skip to content

Commit 069039d

Browse files
committed
Show keyby/indexer in API docs for state
Signed-off-by: Tim Paine <3105306+timkpaine@users.noreply.github.com>
1 parent e81e130 commit 069039d

3 files changed

Lines changed: 34 additions & 2 deletions

File tree

csp_gateway/server/gateway/csp/channels.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ class Channels(BaseModel, metaclass=ChannelsMetaclass):
207207
_feedbacks: Dict[int, FeedbackOutputDef] = PrivateAttr(default_factory=dict)
208208

209209
_state_requests: Dict[Tuple[str, Optional[Union[str, int]]], Any] = PrivateAttr(default_factory=dict)
210+
_state_keybys: Dict[Tuple[str, Optional[Union[str, int]]], Tuple[str, ...]] = PrivateAttr(default_factory=dict)
210211
_last_requests: Dict[Tuple[str, Optional[Union[str, int]]], Any] = PrivateAttr(default_factory=dict)
211212
_next_requests: Dict[Tuple[str, Optional[Union[str, int]]], Any] = PrivateAttr(default_factory=dict)
212213
_send_channels: Dict[Tuple[str, Optional[Union[str, int]]], Any] = PrivateAttr(default_factory=dict)
@@ -732,6 +733,7 @@ def set_state(
732733

733734
# register the trigger
734735
self._state_requests[state_field, indexer] = trigger
736+
self._state_keybys[state_field, indexer] = (keyby,) if isinstance(keyby, str) else tuple(keyby)
735737
else:
736738
# TODO
737739
raise NotImplementedError()

csp_gateway/server/web/app.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,25 @@ def add_state_api(self, field: str) -> None:
396396
model = self._get_field_pydantic_type(name_without_state)
397397
subroute_key = None
398398

399-
add_state_routes(api_router=api_router, field=field, model=model, subroute_key=subroute_key)
399+
# Look up the keyby/indexer this state was registered with (if any),
400+
# so we can surface it in the route's OpenAPI description.
401+
keybys = self.gateway.channels._state_keybys
402+
keyby = ()
403+
indexer = None
404+
for (registered_field, registered_indexer), registered_keyby in keybys.items():
405+
if registered_field == field:
406+
keyby = registered_keyby
407+
indexer = registered_indexer
408+
break
409+
410+
add_state_routes(
411+
api_router=api_router,
412+
field=field,
413+
model=model,
414+
subroute_key=subroute_key,
415+
keyby=keyby,
416+
indexer=indexer,
417+
)
400418

401419
def add_state_available_channels(self, fields: Optional[Set[str]] = None) -> None:
402420
api_router = self.get_router("state")

csp_gateway/server/web/routes/state.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from typing import Any, List, Optional, Set, Union, get_origin
1+
from inspect import cleandoc
2+
from typing import Any, List, Optional, Set, Tuple, Union, get_origin
23

34
from fastapi import APIRouter, HTTPException, Request
45
from pydantic import BaseModel
@@ -20,6 +21,8 @@ def add_state_routes(
2021
field: str = "",
2122
model: Union[BaseModel, List[BaseModel]] = None,
2223
subroute_key: Any = None,
24+
keyby: Tuple[str, ...] = (),
25+
indexer: Optional[Union[str, int]] = None,
2326
) -> None:
2427
if model and get_origin(model) is list:
2528
list_model = model
@@ -29,6 +32,13 @@ def add_state_routes(
2932
# Get the fully qualified type name for the description
3033
fq_type_name = get_fully_qualified_type_name(model)
3134

35+
keyby_lines = []
36+
if keyby:
37+
keyby_lines.append("**Keyed by:** ``{}``".format(", ".join(repr(k) for k in keyby)))
38+
if indexer is not None:
39+
keyby_lines.append("**Indexer:** ``{!r}``".format(indexer))
40+
keyby_prefix = ("\n\n".join(keyby_lines) + "\n\n") if keyby_lines else ""
41+
3242
if subroute_key:
3343
# Prune s_ from start
3444
name_without_state = field[2:]
@@ -88,6 +98,7 @@ async def get_state(key: str, query: Optional[Query] = query_json(), request: Re
8898
responses=get_default_responses(),
8999
response_model=list_model, # type: ignore[valid-type]
90100
name="Get State {} by key".format(name_without_state),
101+
description=keyby_prefix + cleandoc(get_state.__doc__ or ""),
91102
openapi_extra={"type_": fq_type_name} if fq_type_name else None,
92103
)(get_state)
93104

@@ -167,6 +178,7 @@ async def get_state(query: Optional[Query] = query_json(), request: Request = No
167178
responses=get_default_responses(),
168179
response_model=list_model, # type: ignore[valid-type]
169180
name="Get State {}".format(name_without_state),
181+
description=keyby_prefix + cleandoc(get_state.__doc__ or ""),
170182
openapi_extra={"type_": fq_type_name} if fq_type_name else None,
171183
)(get_state)
172184

0 commit comments

Comments
 (0)