Skip to content

Commit c9cbecb

Browse files
committed
Refactorings towards usage as library
1 parent aaf3b21 commit c9cbecb

File tree

24 files changed

+1107
-264
lines changed

24 files changed

+1107
-264
lines changed

dashi/package-lock.json

Lines changed: 739 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dashi/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"prettier": "^3.3.3",
4141
"typescript": "^5.6.2",
4242
"vite": "^5.4.6",
43+
"vite-plugin-dts": "^4.2.4",
4344
"vitest": "^2.1.1"
4445
}
4546
}

dashi/src/components/DashiButton.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ export interface DashiButtonProps extends Omit<ButtonState, "type"> {
1111
function DashiButton({
1212
id,
1313
name,
14-
value,
1514
style,
1615
text,
1716
disabled,
@@ -33,7 +32,6 @@ function DashiButton({
3332
<Button
3433
id={id}
3534
name={name}
36-
value={value}
3735
style={style}
3836
disabled={disabled}
3937
onClick={handleClick}

dashi/vite.config.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
import { defineConfig } from "vitest/config";
22
import react from "@vitejs/plugin-react-swc";
3+
import dts from "vite-plugin-dts";
34

45
// https://vitejs.dev/config/
56
export default defineConfig({
6-
plugins: [react()],
7+
plugins: [
8+
react(),
9+
dts({
10+
include: ["src"],
11+
exclude: ["src/app/**/*", "src/utils/**/*"],
12+
}),
13+
],
714
test: {
815
environment: "jsdom",
916
onConsoleLog: (/*_log: string, _type: "stdout" | "stderr"*/):

dashipy/dashipy/contribs/__init__.py

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from .callback import get_callback_results
2+
from .contributions import get_contributions
3+
from .extensioncontext import ExtensionContext
4+
from .layout import get_layout
5+
from .response import Response
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
from typing import Any
2+
3+
from .extensioncontext import ExtensionContext
4+
from .response import Response
5+
6+
7+
# POST /dashi/callback
8+
def get_callback_results(ext_ctx: ExtensionContext, data: dict[str, Any]):
9+
"""Generate the response for `POST /dashi/callback`.
10+
11+
Args:
12+
ext_ctx: Extension context.
13+
data: A dictionary deserialized from a request JSON body
14+
that may contain a key `callbackRequests` of type `list`.
15+
Returns:
16+
A JSON-serializable list.
17+
"""
18+
# TODO: validate data
19+
callback_requests: list[dict] = data.get("callbackRequests") or []
20+
21+
context = ext_ctx.app_ctx
22+
23+
# TODO: assert correctness, set status code on error
24+
state_change_requests: list[dict] = []
25+
for callback_request in callback_requests:
26+
contrib_point_name: str = callback_request["contribPoint"]
27+
contrib_index: int = callback_request["contribIndex"]
28+
callback_index: int = callback_request["callbackIndex"]
29+
input_values: list = callback_request["inputValues"]
30+
31+
contributions = ext_ctx.contributions[contrib_point_name]
32+
contribution = contributions[contrib_index]
33+
callback = contribution.callbacks[callback_index]
34+
output_values = callback.invoke(context, input_values)
35+
36+
if len(callback.outputs) == 1:
37+
output_values = (output_values,)
38+
39+
state_changes: list[dict] = []
40+
for output_index, output in enumerate(callback.outputs):
41+
output_value = output_values[output_index]
42+
state_changes.append(
43+
{
44+
**output.to_dict(),
45+
"value": (
46+
output_value.to_dict()
47+
if hasattr(output_value, "to_dict")
48+
and callable(output_value.to_dict)
49+
else output_value
50+
),
51+
}
52+
)
53+
54+
state_change_requests.append(
55+
{
56+
"contribPoint": contrib_point_name,
57+
"contribIndex": contrib_index,
58+
"stateChanges": state_changes,
59+
}
60+
)
61+
62+
return Response.success(state_change_requests)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from .extensioncontext import ExtensionContext
2+
from .response import Response
3+
4+
5+
def get_contributions(ext_ctx: ExtensionContext) -> Response:
6+
"""Generate the response for `GET /dashi/contributions`."""
7+
extensions = ext_ctx.extensions
8+
contributions = ext_ctx.contributions
9+
return Response.success(
10+
{
11+
"extensions": [e.to_dict() for e in extensions],
12+
"contributions": {
13+
cpk: [c.to_dict() for c in cpv] for cpk, cpv in contributions.items()
14+
},
15+
}
16+
)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import importlib
2+
from typing import Any
3+
4+
from dashipy.lib import Extension, Contribution
5+
6+
7+
class ExtensionContext:
8+
def __init__(self, app_ctx: Any, extensions: list[Extension]):
9+
self._app_ctx = app_ctx
10+
self._extensions = extensions
11+
contributions_map: dict[str, list[Contribution]] = {}
12+
for contrib_point_name in Extension.get_contrib_point_names():
13+
# noinspection PyTypeChecker
14+
contributions: list[Contribution] = []
15+
for extension in extensions:
16+
contributions.extend(getattr(extension, contrib_point_name))
17+
# noinspection PyTypeChecker
18+
contributions_map[contrib_point_name] = contributions
19+
self._contributions = contributions_map
20+
21+
@property
22+
def app_ctx(self) -> Any:
23+
return self._app_ctx
24+
25+
@property
26+
def extensions(self) -> list[Extension]:
27+
return self._extensions
28+
29+
@property
30+
def contributions(self) -> dict[str, list[Contribution]]:
31+
return self._contributions
32+
33+
@classmethod
34+
def load_extensions(cls, extension_refs: list[str]) -> list[Extension]:
35+
extensions: list[Extension] = []
36+
for ext_ref in extension_refs:
37+
try:
38+
module_name, attr_name = ext_ref.rsplit(".", maxsplit=2)
39+
except (ValueError, AttributeError):
40+
raise TypeError(f"contribution syntax error: {ext_ref!r}")
41+
module = importlib.import_module(module_name)
42+
extension = getattr(module, attr_name)
43+
if not isinstance(extension, Extension):
44+
raise TypeError(
45+
f"extension {ext_ref!r} must refer to an"
46+
f" instance of {Extension.__qualname__!r},"
47+
f" but was {type(extension).__qualname__!r}"
48+
)
49+
extensions.append(extension)
50+
return extensions
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from typing import Any
2+
3+
from .extensioncontext import ExtensionContext
4+
from .response import Response
5+
6+
7+
def get_layout(
8+
ext_ctx: ExtensionContext,
9+
contrib_point_name: str,
10+
contrib_index: int,
11+
data: dict[str, Any],
12+
) -> Response:
13+
"""Generate the response for
14+
`POST /dashi/layout/{contrib_point_name}/{contrib_index}`.
15+
16+
Args:
17+
ext_ctx: Extension context.
18+
contrib_point_name: Contribution point name.
19+
contrib_index: Contribution index.
20+
data: A dictionary deserialized from a request JSON body
21+
that may contain a key `inputValues` of type `list`.
22+
Returns:
23+
A JSON-serializable dictionary.
24+
"""
25+
# TODO: validate data
26+
input_values = data.get("inputValues") or []
27+
28+
try:
29+
contributions = ext_ctx.contributions[contrib_point_name]
30+
except KeyError:
31+
return Response.failed(
32+
404, f"contribution point {contrib_point_name!r} not found"
33+
)
34+
35+
contrib_ref = f"{contrib_point_name}[{contrib_index}]"
36+
37+
try:
38+
contribution = contributions[contrib_index]
39+
except IndexError:
40+
return Response.failed(404, f"contribution {contrib_ref!r} not found")
41+
42+
callback = contribution.layout_callback
43+
if callback is None:
44+
return Response.failed(400, f"contribution {contrib_ref!r} has no layout")
45+
46+
component = callback.invoke(ext_ctx.app_ctx, input_values)
47+
48+
return Response.success(component.to_dict())

0 commit comments

Comments
 (0)