1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
|
"""Class-based function extension base."""
import inspect
from typing import TYPE_CHECKING
from typing import Any
from typing import Callable
from typing import List
if TYPE_CHECKING:
from jsonpath.env import JSONPathEnvironment
from jsonpath.token import Token
from jsonpath.exceptions import JSONPathTypeError
def validate(
_: "JSONPathEnvironment",
func: Callable[..., Any],
args: List[Any],
token: "Token",
) -> List[Any]:
"""Generic validation of function extension arguments using introspection.
RFC 9535 requires us to reject paths that use filter functions with too
many or too few arguments.
"""
params = list(inspect.signature(func).parameters.values())
# Keyword only params are not supported
if [p for p in params if p.kind in (p.KEYWORD_ONLY, p.VAR_KEYWORD)]:
raise JSONPathTypeError(
f"function {token.value!r} requires keyword arguments",
token=token,
)
# Too few args?
positional_args = [
p for p in params if p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD)
]
if len(args) < len(positional_args):
raise JSONPathTypeError(
f"{token.value!r}() requires {len(positional_args)} arguments",
token=token,
)
# Does the signature have var args?
has_var_args = bool([p for p in params if p.kind == p.VAR_POSITIONAL])
# Too many args?
if not has_var_args and len(args) > len(positional_args):
raise JSONPathTypeError(
f"{token.value!r}() requires at most "
f"{len(positional_args) + len(positional_args)} arguments",
token=token,
)
return args
|