jambonz-python-sdk 0.2.0__py3-none-any.whl
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.
- jambonz_python_sdk-0.2.0.dist-info/METADATA +179 -0
- jambonz_python_sdk-0.2.0.dist-info/RECORD +119 -0
- jambonz_python_sdk-0.2.0.dist-info/WHEEL +4 -0
- jambonz_sdk/__init__.py +52 -0
- jambonz_sdk/_signature.py +73 -0
- jambonz_sdk/client/__init__.py +15 -0
- jambonz_sdk/client/api.py +241 -0
- jambonz_sdk/schema/callbacks/amd.schema.json +50 -0
- jambonz_sdk/schema/callbacks/base.schema.json +29 -0
- jambonz_sdk/schema/callbacks/call-status.schema.json +22 -0
- jambonz_sdk/schema/callbacks/conference-status.schema.json +24 -0
- jambonz_sdk/schema/callbacks/conference-wait.schema.json +11 -0
- jambonz_sdk/schema/callbacks/conference.schema.json +11 -0
- jambonz_sdk/schema/callbacks/dequeue.schema.json +19 -0
- jambonz_sdk/schema/callbacks/dial-dtmf.schema.json +18 -0
- jambonz_sdk/schema/callbacks/dial-hold.schema.json +22 -0
- jambonz_sdk/schema/callbacks/dial-refer.schema.json +28 -0
- jambonz_sdk/schema/callbacks/dial.schema.json +31 -0
- jambonz_sdk/schema/callbacks/enqueue-wait.schema.json +17 -0
- jambonz_sdk/schema/callbacks/enqueue.schema.json +27 -0
- jambonz_sdk/schema/callbacks/gather-partial.schema.json +54 -0
- jambonz_sdk/schema/callbacks/gather.schema.json +60 -0
- jambonz_sdk/schema/callbacks/listen.schema.json +21 -0
- jambonz_sdk/schema/callbacks/llm.schema.json +30 -0
- jambonz_sdk/schema/callbacks/message.schema.json +35 -0
- jambonz_sdk/schema/callbacks/pipeline-turn.schema.json +109 -0
- jambonz_sdk/schema/callbacks/play.schema.json +36 -0
- jambonz_sdk/schema/callbacks/session-new.schema.json +143 -0
- jambonz_sdk/schema/callbacks/session-reconnect.schema.json +9 -0
- jambonz_sdk/schema/callbacks/session-redirect.schema.json +38 -0
- jambonz_sdk/schema/callbacks/sip-refer-event.schema.json +20 -0
- jambonz_sdk/schema/callbacks/sip-refer.schema.json +22 -0
- jambonz_sdk/schema/callbacks/sip-request.schema.json +27 -0
- jambonz_sdk/schema/callbacks/transcribe-translation.schema.json +24 -0
- jambonz_sdk/schema/callbacks/transcribe.schema.json +46 -0
- jambonz_sdk/schema/callbacks/tts-streaming-event.schema.json +77 -0
- jambonz_sdk/schema/callbacks/verb-status.schema.json +57 -0
- jambonz_sdk/schema/components/actionHook.schema.json +36 -0
- jambonz_sdk/schema/components/actionHookDelayAction.schema.json +37 -0
- jambonz_sdk/schema/components/amd.schema.json +68 -0
- jambonz_sdk/schema/components/auth.schema.json +18 -0
- jambonz_sdk/schema/components/bidirectionalAudio.schema.json +22 -0
- jambonz_sdk/schema/components/fillerNoise.schema.json +25 -0
- jambonz_sdk/schema/components/llm-base.schema.json +94 -0
- jambonz_sdk/schema/components/recognizer-assemblyAiOptions.schema.json +66 -0
- jambonz_sdk/schema/components/recognizer-awsOptions.schema.json +52 -0
- jambonz_sdk/schema/components/recognizer-azureOptions.schema.json +32 -0
- jambonz_sdk/schema/components/recognizer-cobaltOptions.schema.json +34 -0
- jambonz_sdk/schema/components/recognizer-customOptions.schema.json +27 -0
- jambonz_sdk/schema/components/recognizer-deepgramOptions.schema.json +147 -0
- jambonz_sdk/schema/components/recognizer-elevenlabsOptions.schema.json +39 -0
- jambonz_sdk/schema/components/recognizer-gladiaOptions.schema.json +8 -0
- jambonz_sdk/schema/components/recognizer-googleOptions.schema.json +35 -0
- jambonz_sdk/schema/components/recognizer-houndifyOptions.schema.json +53 -0
- jambonz_sdk/schema/components/recognizer-ibmOptions.schema.json +54 -0
- jambonz_sdk/schema/components/recognizer-nuanceOptions.schema.json +150 -0
- jambonz_sdk/schema/components/recognizer-nvidiaOptions.schema.json +39 -0
- jambonz_sdk/schema/components/recognizer-openaiOptions.schema.json +59 -0
- jambonz_sdk/schema/components/recognizer-sonioxOptions.schema.json +46 -0
- jambonz_sdk/schema/components/recognizer-speechmaticsOptions.schema.json +100 -0
- jambonz_sdk/schema/components/recognizer-verbioOptions.schema.json +46 -0
- jambonz_sdk/schema/components/recognizer.schema.json +216 -0
- jambonz_sdk/schema/components/synthesizer.schema.json +82 -0
- jambonz_sdk/schema/components/target.schema.json +105 -0
- jambonz_sdk/schema/components/vad.schema.json +48 -0
- jambonz_sdk/schema/jambonz-app.schema.json +113 -0
- jambonz_sdk/schema/verbs/alert.schema.json +34 -0
- jambonz_sdk/schema/verbs/answer.schema.json +22 -0
- jambonz_sdk/schema/verbs/conference.schema.json +107 -0
- jambonz_sdk/schema/verbs/config.schema.json +221 -0
- jambonz_sdk/schema/verbs/deepgram_s2s.schema.json +81 -0
- jambonz_sdk/schema/verbs/dequeue.schema.json +51 -0
- jambonz_sdk/schema/verbs/dial.schema.json +200 -0
- jambonz_sdk/schema/verbs/dialogflow.schema.json +148 -0
- jambonz_sdk/schema/verbs/dtmf.schema.json +49 -0
- jambonz_sdk/schema/verbs/dub.schema.json +103 -0
- jambonz_sdk/schema/verbs/elevenlabs_s2s.schema.json +81 -0
- jambonz_sdk/schema/verbs/enqueue.schema.json +53 -0
- jambonz_sdk/schema/verbs/gather.schema.json +190 -0
- jambonz_sdk/schema/verbs/google_s2s.schema.json +42 -0
- jambonz_sdk/schema/verbs/hangup.schema.json +36 -0
- jambonz_sdk/schema/verbs/leave.schema.json +22 -0
- jambonz_sdk/schema/verbs/listen.schema.json +127 -0
- jambonz_sdk/schema/verbs/llm.schema.json +44 -0
- jambonz_sdk/schema/verbs/message.schema.json +82 -0
- jambonz_sdk/schema/verbs/openai_s2s.schema.json +42 -0
- jambonz_sdk/schema/verbs/pause.schema.json +36 -0
- jambonz_sdk/schema/verbs/pipeline.schema.json +240 -0
- jambonz_sdk/schema/verbs/play.schema.json +96 -0
- jambonz_sdk/schema/verbs/redirect.schema.json +34 -0
- jambonz_sdk/schema/verbs/rest_dial.schema.json +113 -0
- jambonz_sdk/schema/verbs/s2s.schema.json +39 -0
- jambonz_sdk/schema/verbs/say.schema.json +107 -0
- jambonz_sdk/schema/verbs/sip-decline.schema.json +58 -0
- jambonz_sdk/schema/verbs/sip-refer.schema.json +58 -0
- jambonz_sdk/schema/verbs/sip-request.schema.json +54 -0
- jambonz_sdk/schema/verbs/stream.schema.json +103 -0
- jambonz_sdk/schema/verbs/tag.schema.json +41 -0
- jambonz_sdk/schema/verbs/transcribe.schema.json +57 -0
- jambonz_sdk/schema/verbs/ultravox_s2s.schema.json +41 -0
- jambonz_sdk/types/__init__.py +139 -0
- jambonz_sdk/types/components.py +250 -0
- jambonz_sdk/types/rest.py +59 -0
- jambonz_sdk/types/session.py +55 -0
- jambonz_sdk/types/verbs.py +572 -0
- jambonz_sdk/validator.py +107 -0
- jambonz_sdk/verb_builder.py +316 -0
- jambonz_sdk/verb_builder.pyi +1133 -0
- jambonz_sdk/verb_registry.py +102 -0
- jambonz_sdk/webhook/__init__.py +10 -0
- jambonz_sdk/webhook/middleware.py +63 -0
- jambonz_sdk/webhook/response.py +43 -0
- jambonz_sdk/websocket/__init__.py +15 -0
- jambonz_sdk/websocket/audio_client.py +11 -0
- jambonz_sdk/websocket/audio_stream.py +151 -0
- jambonz_sdk/websocket/client.py +165 -0
- jambonz_sdk/websocket/endpoint.py +193 -0
- jambonz_sdk/websocket/router.py +87 -0
- jambonz_sdk/websocket/session.py +259 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
"""VerbBuilder base class with auto-generated chainable verb methods.
|
|
2
|
+
|
|
3
|
+
Methods are generated at import time from JSON Schema files + the verb registry.
|
|
4
|
+
When the schema changes, the SDK automatically picks up new parameters —
|
|
5
|
+
no manual method signatures to maintain.
|
|
6
|
+
|
|
7
|
+
Each generated method has a real ``inspect.Signature`` with typed parameters
|
|
8
|
+
so IDEs (VS Code, PyCharm) show proper autocomplete and type hints.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import inspect
|
|
14
|
+
import json
|
|
15
|
+
import logging
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Any, Union
|
|
19
|
+
|
|
20
|
+
if sys.version_info >= (3, 11):
|
|
21
|
+
from typing import Self
|
|
22
|
+
else:
|
|
23
|
+
from typing_extensions import Self
|
|
24
|
+
|
|
25
|
+
from jambonz_sdk.types.verbs import AnyVerb
|
|
26
|
+
from jambonz_sdk.verb_registry import VERB_DEFS, VerbDef
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger("jambonz_sdk.verb_builder")
|
|
29
|
+
|
|
30
|
+
# ── JSON Schema type → Python type mapping ────────────────────────────
|
|
31
|
+
|
|
32
|
+
_TYPE_ANNOTATION_MAP: dict[str, type | object] = {
|
|
33
|
+
"string": str,
|
|
34
|
+
"number": Union[int, float],
|
|
35
|
+
"integer": int,
|
|
36
|
+
"boolean": bool,
|
|
37
|
+
"object": dict,
|
|
38
|
+
"array": list,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
_TYPE_STR_MAP: dict[str, str] = {
|
|
42
|
+
"string": "str",
|
|
43
|
+
"number": "int | float",
|
|
44
|
+
"integer": "int",
|
|
45
|
+
"boolean": "bool",
|
|
46
|
+
"object": "dict[str, Any]",
|
|
47
|
+
"array": "list[Any]",
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _resolve_type(prop_schema: Any) -> type | object:
|
|
52
|
+
"""Convert a JSON Schema property definition to a Python type annotation."""
|
|
53
|
+
if isinstance(prop_schema, str):
|
|
54
|
+
# Backward compat: simple type string (shouldn't happen with JSON Schema)
|
|
55
|
+
return _TYPE_ANNOTATION_MAP.get(prop_schema, Any)
|
|
56
|
+
|
|
57
|
+
if not isinstance(prop_schema, dict):
|
|
58
|
+
return Any
|
|
59
|
+
|
|
60
|
+
# $ref → component reference → dict
|
|
61
|
+
if "$ref" in prop_schema:
|
|
62
|
+
return dict
|
|
63
|
+
|
|
64
|
+
# const → the type of the const value
|
|
65
|
+
if "const" in prop_schema:
|
|
66
|
+
val = prop_schema["const"]
|
|
67
|
+
return type(val)
|
|
68
|
+
|
|
69
|
+
# oneOf → union of the branch types
|
|
70
|
+
if "oneOf" in prop_schema:
|
|
71
|
+
parts: list[type | object] = []
|
|
72
|
+
for branch in prop_schema["oneOf"]:
|
|
73
|
+
resolved = _resolve_type(branch)
|
|
74
|
+
if resolved is Union[int, float]:
|
|
75
|
+
parts.extend([int, float])
|
|
76
|
+
elif resolved not in parts:
|
|
77
|
+
parts.append(resolved)
|
|
78
|
+
# Deduplicate while preserving order
|
|
79
|
+
seen: set[type | object] = set()
|
|
80
|
+
unique = []
|
|
81
|
+
for p in parts:
|
|
82
|
+
if p not in seen:
|
|
83
|
+
seen.add(p)
|
|
84
|
+
unique.append(p)
|
|
85
|
+
if len(unique) == 1:
|
|
86
|
+
return unique[0]
|
|
87
|
+
return Union[tuple(unique)]
|
|
88
|
+
|
|
89
|
+
# Simple type
|
|
90
|
+
schema_type = prop_schema.get("type")
|
|
91
|
+
if isinstance(schema_type, str):
|
|
92
|
+
return _TYPE_ANNOTATION_MAP.get(schema_type, Any)
|
|
93
|
+
|
|
94
|
+
# Array of types
|
|
95
|
+
if isinstance(schema_type, list):
|
|
96
|
+
parts = []
|
|
97
|
+
for t in schema_type:
|
|
98
|
+
resolved = _TYPE_ANNOTATION_MAP.get(t, Any)
|
|
99
|
+
if resolved is Union[int, float]:
|
|
100
|
+
parts.extend([int, float])
|
|
101
|
+
elif resolved not in parts:
|
|
102
|
+
parts.append(resolved)
|
|
103
|
+
if len(parts) == 1:
|
|
104
|
+
return parts[0]
|
|
105
|
+
return Union[tuple(parts)]
|
|
106
|
+
|
|
107
|
+
return Any
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _python_type_str(prop_schema: Any) -> str:
|
|
111
|
+
"""Convert a JSON Schema property definition to a human-readable type string."""
|
|
112
|
+
if isinstance(prop_schema, str):
|
|
113
|
+
return _TYPE_STR_MAP.get(prop_schema, "Any")
|
|
114
|
+
|
|
115
|
+
if not isinstance(prop_schema, dict):
|
|
116
|
+
return "Any"
|
|
117
|
+
|
|
118
|
+
if "$ref" in prop_schema:
|
|
119
|
+
return "dict[str, Any]"
|
|
120
|
+
|
|
121
|
+
if "const" in prop_schema:
|
|
122
|
+
return repr(type(prop_schema["const"]).__name__)
|
|
123
|
+
|
|
124
|
+
if "oneOf" in prop_schema:
|
|
125
|
+
parts = [_python_type_str(branch) for branch in prop_schema["oneOf"]]
|
|
126
|
+
return " | ".join(dict.fromkeys(parts))
|
|
127
|
+
|
|
128
|
+
schema_type = prop_schema.get("type")
|
|
129
|
+
if isinstance(schema_type, str):
|
|
130
|
+
return _TYPE_STR_MAP.get(schema_type, "Any")
|
|
131
|
+
if isinstance(schema_type, list):
|
|
132
|
+
parts = [_TYPE_STR_MAP.get(t, "Any") for t in schema_type]
|
|
133
|
+
return " | ".join(dict.fromkeys(parts))
|
|
134
|
+
|
|
135
|
+
return "Any"
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
# ── Load JSON Schemas ──────────────────────────────────────────────────
|
|
139
|
+
|
|
140
|
+
def _load_schemas() -> dict[str, Any]:
|
|
141
|
+
"""Load verb JSON Schemas bundled alongside this package.
|
|
142
|
+
|
|
143
|
+
Returns a dict mapping verb spec names (e.g. 'say', 'sip:decline')
|
|
144
|
+
to their schema dicts, with a 'properties' key and optionally 'required'.
|
|
145
|
+
"""
|
|
146
|
+
schema_dir = Path(__file__).resolve().parent / "schema" / "verbs"
|
|
147
|
+
schemas: dict[str, Any] = {}
|
|
148
|
+
|
|
149
|
+
if not schema_dir.is_dir():
|
|
150
|
+
logger.warning("Schema directory not found: %s", schema_dir)
|
|
151
|
+
return schemas
|
|
152
|
+
|
|
153
|
+
for schema_file in sorted(schema_dir.glob("*.schema.json")):
|
|
154
|
+
with schema_file.open() as f:
|
|
155
|
+
schema = json.load(f)
|
|
156
|
+
|
|
157
|
+
# Derive the spec name from the $id or filename
|
|
158
|
+
schema_id = schema.get("$id", "")
|
|
159
|
+
if schema_id:
|
|
160
|
+
# e.g. "https://jambonz.org/schema/verbs/say" → "say"
|
|
161
|
+
# e.g. "https://jambonz.org/schema/verbs/sip:decline" → "sip:decline"
|
|
162
|
+
spec_name = schema_id.rsplit("/", 1)[-1]
|
|
163
|
+
else:
|
|
164
|
+
# Fallback: filename without .schema.json
|
|
165
|
+
spec_name = schema_file.stem.replace(".schema", "")
|
|
166
|
+
|
|
167
|
+
# Collect properties, skipping 'verb' (it's a const, not a user param)
|
|
168
|
+
properties = {}
|
|
169
|
+
for prop_name, prop_def in schema.get("properties", {}).items():
|
|
170
|
+
if prop_name == "verb":
|
|
171
|
+
continue
|
|
172
|
+
properties[prop_name] = prop_def
|
|
173
|
+
|
|
174
|
+
# Handle allOf (used by vendor-specific s2s verbs that extend llm-base)
|
|
175
|
+
for entry in schema.get("allOf", []):
|
|
176
|
+
if "properties" in entry:
|
|
177
|
+
for prop_name, prop_def in entry["properties"].items():
|
|
178
|
+
if prop_name == "verb":
|
|
179
|
+
continue
|
|
180
|
+
properties[prop_name] = prop_def
|
|
181
|
+
|
|
182
|
+
schemas[spec_name] = {
|
|
183
|
+
"properties": properties,
|
|
184
|
+
"required": schema.get("required", []),
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return schemas
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
_SPECS: dict[str, Any] = _load_schemas()
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
# ── Method factory ──────────────────────────────────────────────────
|
|
194
|
+
|
|
195
|
+
def _make_verb_method(verb_def: VerbDef, spec: dict[str, Any]) -> Any:
|
|
196
|
+
"""Create a verb method with a real typed signature from the spec.
|
|
197
|
+
|
|
198
|
+
Each generated method has:
|
|
199
|
+
- ``inspect.Signature`` with keyword-only parameters (default ``None``)
|
|
200
|
+
- ``__annotations__`` with resolved Python types (not ``Any``)
|
|
201
|
+
- Docstring with parameter types and required markers
|
|
202
|
+
"""
|
|
203
|
+
properties = spec.get("properties", {})
|
|
204
|
+
required = set(spec.get("required", []))
|
|
205
|
+
json_verb = verb_def.json_verb
|
|
206
|
+
inject = verb_def.inject
|
|
207
|
+
|
|
208
|
+
def verb_method(self: VerbBuilder, **kwargs: Any) -> Self:
|
|
209
|
+
data: dict[str, Any] = {}
|
|
210
|
+
if inject:
|
|
211
|
+
data.update(inject)
|
|
212
|
+
for key, value in kwargs.items():
|
|
213
|
+
if value is None:
|
|
214
|
+
continue
|
|
215
|
+
if key == "from_":
|
|
216
|
+
data["from"] = value
|
|
217
|
+
else:
|
|
218
|
+
data[key] = value
|
|
219
|
+
verb: dict[str, Any] = {"verb": json_verb, **data}
|
|
220
|
+
self._verbs.append(verb) # type: ignore[arg-type]
|
|
221
|
+
return self
|
|
222
|
+
|
|
223
|
+
# ── Build inspect.Signature with typed keyword-only params ──────
|
|
224
|
+
params = [inspect.Parameter("self", inspect.Parameter.POSITIONAL_OR_KEYWORD)]
|
|
225
|
+
annotations: dict[str, Any] = {}
|
|
226
|
+
|
|
227
|
+
for prop_name, prop_spec in properties.items():
|
|
228
|
+
py_name = "from_" if prop_name == "from" else prop_name
|
|
229
|
+
py_type = _resolve_type(prop_spec)
|
|
230
|
+
params.append(inspect.Parameter(
|
|
231
|
+
py_name,
|
|
232
|
+
inspect.Parameter.KEYWORD_ONLY,
|
|
233
|
+
default=None,
|
|
234
|
+
annotation=py_type,
|
|
235
|
+
))
|
|
236
|
+
annotations[py_name] = py_type
|
|
237
|
+
|
|
238
|
+
# Add **kwargs for forward compatibility
|
|
239
|
+
params.append(inspect.Parameter("kwargs", inspect.Parameter.VAR_KEYWORD))
|
|
240
|
+
annotations["return"] = Self
|
|
241
|
+
|
|
242
|
+
verb_method.__signature__ = inspect.Signature(params)
|
|
243
|
+
verb_method.__annotations__ = annotations
|
|
244
|
+
|
|
245
|
+
# ── Build docstring ─────────────────────────────────────────────
|
|
246
|
+
doc_lines = [verb_def.doc, ""]
|
|
247
|
+
if required:
|
|
248
|
+
doc_lines.append(f"Required: {', '.join(sorted(required))}")
|
|
249
|
+
doc_lines.append("")
|
|
250
|
+
doc_lines.append("Args:")
|
|
251
|
+
for prop_name, prop_spec in properties.items():
|
|
252
|
+
py_name = "from_" if prop_name == "from" else prop_name
|
|
253
|
+
py_type_str = _python_type_str(prop_spec)
|
|
254
|
+
req_marker = " **(required)**" if prop_name in required else ""
|
|
255
|
+
doc_lines.append(f" {py_name} ({py_type_str}):{req_marker}")
|
|
256
|
+
doc_lines.append("")
|
|
257
|
+
doc_lines.append("Returns:")
|
|
258
|
+
doc_lines.append(" self for chaining.")
|
|
259
|
+
|
|
260
|
+
verb_method.__doc__ = "\n".join(doc_lines)
|
|
261
|
+
verb_method.__name__ = verb_def.method_name
|
|
262
|
+
verb_method.__qualname__ = f"VerbBuilder.{verb_def.method_name}"
|
|
263
|
+
|
|
264
|
+
return verb_method
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
# ── VerbBuilder class ───────────────────────────────────────────────
|
|
268
|
+
|
|
269
|
+
class VerbBuilder:
|
|
270
|
+
"""Builds an ordered list of jambonz verbs using a fluent API.
|
|
271
|
+
|
|
272
|
+
All verb methods are auto-generated from JSON Schema files and accept
|
|
273
|
+
keyword arguments matching the verb's specification. Methods return
|
|
274
|
+
``self`` for chaining.
|
|
275
|
+
|
|
276
|
+
Example::
|
|
277
|
+
|
|
278
|
+
builder = VerbBuilder()
|
|
279
|
+
verbs = (
|
|
280
|
+
builder
|
|
281
|
+
.say(text="Hello!")
|
|
282
|
+
.pause(length=1)
|
|
283
|
+
.gather(input=["speech"], actionHook="/result", timeout=10)
|
|
284
|
+
.hangup()
|
|
285
|
+
.to_list()
|
|
286
|
+
)
|
|
287
|
+
"""
|
|
288
|
+
|
|
289
|
+
def __init__(self) -> None:
|
|
290
|
+
self._verbs: list[AnyVerb] = []
|
|
291
|
+
|
|
292
|
+
def to_list(self) -> list[AnyVerb]:
|
|
293
|
+
"""Return the verb list and reset the builder."""
|
|
294
|
+
verbs = list(self._verbs)
|
|
295
|
+
self._verbs = []
|
|
296
|
+
return verbs
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
# ── Attach generated methods to VerbBuilder ─────────────────────────
|
|
300
|
+
|
|
301
|
+
def _build_methods() -> None:
|
|
302
|
+
"""Generate and attach verb methods to VerbBuilder from schemas + registry."""
|
|
303
|
+
for verb_def in VERB_DEFS:
|
|
304
|
+
spec = _SPECS.get(verb_def.spec_name)
|
|
305
|
+
if spec is None:
|
|
306
|
+
logger.warning(
|
|
307
|
+
"Schema for '%s' not found for method '%s' — skipping",
|
|
308
|
+
verb_def.spec_name,
|
|
309
|
+
verb_def.method_name,
|
|
310
|
+
)
|
|
311
|
+
continue
|
|
312
|
+
method = _make_verb_method(verb_def, spec)
|
|
313
|
+
setattr(VerbBuilder, verb_def.method_name, method)
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
_build_methods()
|