feat: deliver Python workflow client

This commit is contained in:
lda
2026-08-31 02:49:07 +07:00 Verified
parent d53b96fd7c
commit 5315d4b66e
18 changed files with 717 additions and 19 deletions
+103
View File
@@ -0,0 +1,103 @@
"""Small, inert renderers shared by the public workflow-client snapshots.
Representations are a debugging aid, not another client operation. This
module deliberately accepts already-loaded values and never knows about the
workflow transport port. The same bounded projector is used for plain and
HTML representations so notebooks cannot accidentally expose an unbounded
trace, output, or credential-shaped value.
"""
from __future__ import annotations
import html
import json
from collections.abc import Mapping, Sequence
_SECRET_KEY_PARTS = (
"authorization",
"cookie",
"set-cookie",
"token",
"secret",
"password",
"api_key",
"api-key",
)
_MAX_DEPTH = 2
_MAX_ITEMS = 8
_MAX_STRING = 160
_MAX_RENDERED = 1_200
def _secret_key(key: object) -> bool:
lowered = str(key).lower()
return any(part in lowered for part in _SECRET_KEY_PARTS)
def bounded_value(value: object, *, depth: int = 0) -> object:
"""Project loaded JSON-like data into a small, secret-safe preview."""
if depth >= _MAX_DEPTH:
return "[truncated]"
if isinstance(value, str):
return value if len(value) <= _MAX_STRING else value[:_MAX_STRING] + ""
if value is None or isinstance(value, bool | int | float):
return value
if isinstance(value, Mapping):
items = list(value.items())
preview = {
str(key): "[redacted]"
if _secret_key(key)
else bounded_value(item, depth=depth + 1)
for key, item in items[:_MAX_ITEMS]
}
if len(items) > _MAX_ITEMS:
preview[""] = f"{len(items) - _MAX_ITEMS} more entries"
return preview
if isinstance(value, Sequence) and not isinstance(value, str | bytes | bytearray):
items = list(value)
preview = [bounded_value(item, depth=depth + 1) for item in items[:_MAX_ITEMS]]
if len(items) > _MAX_ITEMS:
preview.append(f"{len(items) - _MAX_ITEMS} more items")
return preview
rendered = repr(value)
return rendered if len(rendered) <= _MAX_STRING else rendered[:_MAX_STRING] + ""
def preview(value: object) -> str:
"""Render a bounded value without allowing an object's repr to grow freely."""
try:
rendered = json.dumps(bounded_value(value), sort_keys=True, default=str)
except TypeError, ValueError:
rendered = str(bounded_value(value))
return rendered[:_MAX_RENDERED] + ("" if len(rendered) > _MAX_RENDERED else "")
def short_repr(type_name: str, **fields: object) -> str:
"""Build a compact Python repr from already-loaded field values."""
body = ", ".join(f"{name}={preview(value)}" for name, value in fields.items())
rendered = f"{type_name}({body})"
return rendered[:_MAX_RENDERED] + ("" if len(rendered) > _MAX_RENDERED else "")
def html_repr(type_name: str, **fields: object) -> str:
"""Build a bounded HTML table suitable for IPython rich display."""
def html_preview(value: object) -> str:
rendered = preview(value)
return rendered[:400] + ("" if len(rendered) > 400 else "")
rows = "".join(
'<tr><th scope="row">'
+ html.escape(name)
+ "</th><td><code>"
+ html.escape(html_preview(value))
+ "</code></td></tr>"
for name, value in fields.items()
)
return (
'<div class="wf-client-repr"><strong>'
+ html.escape(type_name)
+ "</strong><table><tbody>"
+ rows
+ "</tbody></table></div>"
)