Coverage for src / invariant / invocation.py: 91.30%
23 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-05-08 09:24 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-05-08 09:24 +0000
1"""Shared operation invocation helpers."""
3import inspect
4from collections.abc import Callable
5from typing import Any
7from invariant.cacheable import is_cacheable
10def invoke_op(op: Callable[..., Any], op_name: str, manifest: dict[str, Any]) -> Any:
11 """Invoke an operation with kwargs dispatch and return validation.
13 Args:
14 op: The callable operation to invoke.
15 op_name: The name of the operation (for error messages).
16 manifest: The manifest dictionary mapping parameter names to values.
18 Returns:
19 The operation result (native type or ICacheable domain type).
21 Raises:
22 ValueError: If required parameters are missing.
23 TypeError: If return value is not cacheable.
24 """
25 sig = inspect.signature(op)
26 kwargs: dict[str, Any] = {}
28 for name, param in sig.parameters.items():
29 if name in manifest:
30 kwargs[name] = manifest[name]
31 elif (
32 param.default is not inspect.Parameter.empty
33 or param.kind == inspect.Parameter.VAR_KEYWORD
34 ):
35 pass
36 else:
37 raise ValueError(f"Op '{op_name}': missing required parameter '{name}'")
39 has_var_kwargs = any(
40 p.kind == inspect.Parameter.VAR_KEYWORD for p in sig.parameters.values()
41 )
42 if has_var_kwargs:
43 for key, val in manifest.items():
44 if key not in kwargs:
45 kwargs[key] = val
47 result = op(**kwargs)
49 if not is_cacheable(result):
50 raise TypeError(
51 f"Op '{op_name}' returned {type(result).__name__}, "
52 f"which is not a cacheable type"
53 )
55 return result
58__all__ = ["invoke_op"]