Skip to content

Commit e3f6852

Browse files
committed
Add docs and metadata to the services/handlers
1 parent 8935b4d commit e3f6852

File tree

5 files changed

+79
-33
lines changed

5 files changed

+79
-33
lines changed

python/restate/discovery.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@
2121
# pylint: disable=C0115
2222
# pylint: disable=C0103
2323
# pylint: disable=W0622
24+
# pylint: disable=R0913,
25+
# pylint: disable=R0917,
2426

2527
import json
2628
import typing
2729
from enum import Enum
28-
from typing import Optional, Any, List, get_args, get_origin
30+
from typing import Dict, Optional, Any, List, get_args, get_origin
2931

3032

3133
from restate.endpoint import Endpoint as RestateEndpoint
@@ -58,17 +60,21 @@ def __init__(self, contentType: str, setContentTypeIfEmpty: bool, jsonSchema: Op
5860
self.jsonSchema = jsonSchema
5961

6062
class Handler:
61-
def __init__(self, name: str, ty: Optional[ServiceHandlerType] = None, input: Optional[InputPayload] = None, output: Optional[OutputPayload] = None):
63+
def __init__(self, name: str, ty: Optional[ServiceHandlerType] = None, input: Optional[InputPayload] = None, output: Optional[OutputPayload] = None, description: Optional[str] = None, metadata: Optional[Dict[str, str]] = None):
6264
self.name = name
6365
self.ty = ty
6466
self.input = input
6567
self.output = output
68+
self.documentation = description
69+
self.metadata = metadata
6670

6771
class Service:
68-
def __init__(self, name: str, ty: ServiceType, handlers: List[Handler]):
72+
def __init__(self, name: str, ty: ServiceType, handlers: List[Handler], description: Optional[str] = None, metadata: Optional[Dict[str, str]] = None):
6973
self.name = name
7074
self.ty = ty
7175
self.handlers = handlers
76+
self.documentation = description
77+
self.metadata = metadata
7278

7379
class Endpoint:
7480
def __init__(self, protocolMode: ProtocolMode, minProtocolVersion: int, maxProtocolVersion: int, services: List[Service]):
@@ -182,10 +188,16 @@ def compute_discovery(endpoint: RestateEndpoint, discovered_as : typing.Literal[
182188
contentType=handler.handler_io.content_type,
183189
jsonSchema=json_schema_from_type_hint(handler.handler_io.output_type))
184190
# add the handler
185-
service_handlers.append(Handler(name=handler.name, ty=ty, input=inp, output=out))
186-
191+
service_handlers.append(Handler(name=handler.name,
192+
ty=ty,
193+
input=inp,
194+
output=out,
195+
description=handler.description,
196+
metadata=handler.metadata))
187197
# add the service
188-
services.append(Service(name=service.name, ty=service_type, handlers=service_handlers))
198+
description = service.service_tag.description
199+
metadata = service.service_tag.metadata
200+
services.append(Service(name=service.name, ty=service_type, handlers=service_handlers, description=description, metadata=metadata))
189201

190202
if endpoint.protocol:
191203
protocol_mode = PROTOCOL_MODES[endpoint.protocol]

python/restate/handler.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
from dataclasses import dataclass
1919
from inspect import Signature
20-
from typing import Any, Callable, Awaitable, Generic, Literal, Optional, TypeVar
20+
from typing import Any, Callable, Awaitable, Dict, Generic, Literal, Optional, TypeVar
2121

2222
from restate.exceptions import TerminalError
2323
from restate.serde import JsonSerde, Serde, PydanticJsonSerde
@@ -52,6 +52,8 @@ class ServiceTag:
5252
"""
5353
kind: Literal["object", "service", "workflow"]
5454
name: str
55+
description: Optional[str] = None
56+
metadata: Optional[Dict[str, str]] = None
5557

5658
@dataclass
5759
class TypeHint(Generic[T]):
@@ -114,6 +116,7 @@ def extract_io_type_hints(handler_io: HandlerIO[I, O], signature: Signature):
114116
if isinstance(handler_io.output_serde, JsonSerde): # type: ignore
115117
handler_io.output_serde = PydanticJsonSerde(annotation)
116118

119+
# pylint: disable=R0902
117120
@dataclass
118121
class Handler(Generic[I, O]):
119122
"""
@@ -125,6 +128,8 @@ class Handler(Generic[I, O]):
125128
name: str
126129
fn: Callable[[Any, I], Awaitable[O]] | Callable[[Any], Awaitable[O]]
127130
arity: int
131+
description: Optional[str] = None
132+
metadata: Optional[Dict[str, str]] = None
128133

129134

130135
# disable too many arguments warning
@@ -135,7 +140,9 @@ def make_handler(service_tag: ServiceTag,
135140
name: str | None,
136141
kind: Optional[Literal["exclusive", "shared", "workflow"]],
137142
wrapped: Any,
138-
signature: Signature) -> Handler[I, O]:
143+
signature: Signature,
144+
description: Optional[str] = None,
145+
metadata: Optional[Dict[str, str]] = None) -> Handler[I, O]:
139146
"""
140147
Factory function to create a handler.
141148
"""
@@ -152,12 +159,14 @@ def make_handler(service_tag: ServiceTag,
152159
arity = len(signature.parameters)
153160
extract_io_type_hints(handler_io, signature)
154161

155-
handler = Handler[I, O](service_tag,
156-
handler_io,
157-
kind,
158-
handler_name,
159-
wrapped,
160-
arity)
162+
handler = Handler[I, O](service_tag=service_tag,
163+
handler_io=handler_io,
164+
kind=kind,
165+
name=handler_name,
166+
fn=wrapped,
167+
arity=arity,
168+
description=description,
169+
metadata=metadata)
161170

162171
vars(wrapped)[RESTATE_UNIQUE_HANDLER_SYMBOL] = handler
163172
return handler

python/restate/object.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import typing
1919

2020
from restate.serde import Serde, JsonSerde
21-
from .handler import HandlerIO, ServiceTag, make_handler
21+
from restate.handler import Handler, HandlerIO, ServiceTag, make_handler
2222

2323
I = typing.TypeVar('I')
2424
O = typing.TypeVar('O')
@@ -36,10 +36,16 @@ class VirtualObject:
3636
3737
Args:
3838
name (str): The name of the object.
39+
description (str): The description of the object.
40+
metadata (dict): The metadata of the object.
3941
"""
4042

41-
def __init__(self, name):
42-
self.service_tag = ServiceTag("object", name)
43+
handlers: typing.Dict[str, Handler[typing.Any, typing.Any]]
44+
45+
def __init__(self, name,
46+
description: typing.Optional[str] = None,
47+
metadata: typing.Optional[typing.Dict[str, str]]=None):
48+
self.service_tag = ServiceTag("object", name, description, metadata)
4349
self.handlers = {}
4450

4551
@property
@@ -55,7 +61,8 @@ def handler(self,
5561
accept: str = "application/json",
5662
content_type: str = "application/json",
5763
input_serde: Serde[I] = JsonSerde[I](), # type: ignore
58-
output_serde: Serde[O] = JsonSerde[O]()) -> typing.Callable: # type: ignore
64+
output_serde: Serde[O] = JsonSerde[O](), # type: ignore
65+
metadata: typing.Optional[dict] = None) -> typing.Callable:
5966
"""
6067
Decorator for defining a handler function.
6168
@@ -86,7 +93,7 @@ def wrapped(*args, **kwargs):
8693
return fn(*args, **kwargs)
8794

8895
signature = inspect.signature(fn, eval_str=True)
89-
handler = make_handler(self.service_tag, handler_io, name, kind, wrapped, signature)
96+
handler = make_handler(self.service_tag, handler_io, name, kind, wrapped, signature, inspect.getdoc(fn), metadata)
9097
self.handlers[handler.name] = handler
9198
return wrapped
9299

python/restate/service.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import typing
2020

2121
from restate.serde import Serde, JsonSerde
22-
from .handler import Handler, HandlerIO, ServiceTag, make_handler
22+
from restate.handler import Handler, HandlerIO, ServiceTag, make_handler
2323

2424
I = typing.TypeVar('I')
2525
O = typing.TypeVar('O')
@@ -39,8 +39,10 @@ class Service:
3939
name (str): The name of the service.
4040
"""
4141

42-
def __init__(self, name: str) -> None:
43-
self.service_tag = ServiceTag("service", name)
42+
def __init__(self, name: str,
43+
description: typing.Optional[str] = None,
44+
metadata: typing.Optional[typing.Dict[str, str]] = None) -> None:
45+
self.service_tag = ServiceTag("service", name, description, metadata)
4446
self.handlers: typing.Dict[str, Handler] = {}
4547

4648
@property
@@ -55,7 +57,8 @@ def handler(self,
5557
accept: str = "application/json",
5658
content_type: str = "application/json",
5759
input_serde: Serde[I] = JsonSerde[I](), # type: ignore
58-
output_serde: Serde[O] = JsonSerde[O]()) -> typing.Callable: # type: ignore
60+
output_serde: Serde[O] = JsonSerde[O](), # type: ignore
61+
metadata: typing.Optional[typing.Dict[str, str]] = None) -> typing.Callable:
5962
"""
6063
Decorator for defining a handler function.
6164
@@ -85,7 +88,7 @@ def wrapped(*args, **kwargs):
8588
return fn(*args, **kwargs)
8689

8790
signature = inspect.signature(fn, eval_str=True)
88-
handler = make_handler(self.service_tag, handler_io, name, None, wrapped, signature)
91+
handler = make_handler(self.service_tag, handler_io, name, None, wrapped, signature, inspect.getdoc(fn), metadata)
8992
self.handlers[handler.name] = handler
9093
return wrapped
9194

python/restate/workflow.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import typing
2020

2121
from restate.serde import Serde, JsonSerde
22-
from .handler import HandlerIO, ServiceTag, make_handler
22+
from restate.handler import Handler, HandlerIO, ServiceTag, make_handler
2323

2424
I = typing.TypeVar('I')
2525
O = typing.TypeVar('O')
@@ -42,8 +42,10 @@ class Workflow:
4242
name (str): The name of the object.
4343
"""
4444

45-
def __init__(self, name):
46-
self.service_tag = ServiceTag("workflow", name)
45+
handlers: typing.Dict[str, Handler[typing.Any, typing.Any]]
46+
47+
def __init__(self, name, description: typing.Optional[str] = None, metadata: typing.Optional[typing.Dict[str, str]] = None):
48+
self.service_tag = ServiceTag("workflow", name, description, metadata)
4749
self.handlers = {}
4850

4951
@property
@@ -58,33 +60,37 @@ def main(self,
5860
accept: str = "application/json",
5961
content_type: str = "application/json",
6062
input_serde: Serde[I] = JsonSerde[I](), # type: ignore
61-
output_serde: Serde[O] = JsonSerde[O]()) -> typing.Callable: # type: ignore
63+
output_serde: Serde[O] = JsonSerde[O](), # type: ignore
64+
metadata: typing.Optional[typing.Dict[str, str]] = None) -> typing.Callable: # type: ignore
6265
"""Mark this handler as a workflow entry point"""
6366
return self._add_handler(name,
6467
kind="workflow",
6568
accept=accept,
6669
content_type=content_type,
6770
input_serde=input_serde,
68-
output_serde=output_serde)
71+
output_serde=output_serde,
72+
metadata=metadata)
6973

7074
def handler(self,
7175
name: typing.Optional[str] = None,
7276
accept: str = "application/json",
7377
content_type: str = "application/json",
7478
input_serde: Serde[I] = JsonSerde[I](), # type: ignore
75-
output_serde: Serde[O] = JsonSerde[O]()) -> typing.Callable: # type: ignore
79+
output_serde: Serde[O] = JsonSerde[O](), # type: ignore
80+
metadata: typing.Optional[typing.Dict[str, str]] = None) -> typing.Callable:
7681
"""
7782
Decorator for defining a handler function.
7883
"""
79-
return self._add_handler(name, "shared", accept, content_type, input_serde, output_serde)
84+
return self._add_handler(name, "shared", accept, content_type, input_serde, output_serde, metadata)
8085

8186
def _add_handler(self,
8287
name: typing.Optional[str] = None,
8388
kind: typing.Literal["workflow", "shared", "exclusive"] = "shared",
8489
accept: str = "application/json",
8590
content_type: str = "application/json",
8691
input_serde: Serde[I] = JsonSerde[I](), # type: ignore
87-
output_serde: Serde[O] = JsonSerde[O]()) -> typing.Callable: # type: ignore
92+
output_serde: Serde[O] = JsonSerde[O](), # type: ignore
93+
metadata: typing.Optional[typing.Dict[str, str]] = None) -> typing.Callable: # type: ignore
8894
"""
8995
Decorator for defining a handler function.
9096
@@ -94,6 +100,7 @@ def _add_handler(self,
94100
content_type: The content type of the request. Default "application/json".
95101
serializer: The serializer function to convert the response object to bytes.
96102
deserializer: The deserializer function to convert the request bytes to an object.
103+
metadata: An optional dictionary of metadata.
97104
98105
Returns:
99106
Callable: The decorated function.
@@ -115,7 +122,15 @@ def wrapped(*args, **kwargs):
115122
return fn(*args, **kwargs)
116123

117124
signature = inspect.signature(fn, eval_str=True)
118-
handler = make_handler(self.service_tag, handler_io, name, kind, wrapped, signature)
125+
description = inspect.getdoc(fn)
126+
handler = make_handler(service_tag=self.service_tag,
127+
handler_io=handler_io,
128+
name=name,
129+
kind=kind,
130+
wrapped=wrapped,
131+
signature=signature,
132+
description=description,
133+
metadata=metadata)
119134
self.handlers[handler.name] = handler
120135
return wrapped
121136

0 commit comments

Comments
 (0)