Skip to content

Typing

jsonrpcclient ships type hints and a py.typed marker, so mypy, pyright and your editor check your calls without any stubs. CI checks the library and its typing examples with mypy and pyright in strict mode.

What parse returns

parse has overloads, so the type depends on what you pass:

You pass You get
a dict Ok | Error
a list (a batch) Iterator[Ok | Error]
something typed Any Any

parse_json takes a string, so a type checker can't tell one response from a batch. It returns Ok | Error | Iterator[Ok | Error].

New in 4.0.4

Before 4.0.4, parse_json was typed as returning Any, and parse had no overloads.

Narrow before you use .result

result only exists on Ok. So this fails type checking, even though it runs when the call succeeds:

from jsonrpcclient import parse

parsed = parse({"jsonrpc": "2.0", "result": "pong", "id": 1})
print(parsed.result)  # mypy: Item "Error" of "Ok | Error" has no attribute "result"
Output
pong

It's also a real bug: when the server sends an error, parsed is an Error and .result raises AttributeError. Check the type first with isinstance or match, as in Responses. In a quick script you can assert it instead:

from jsonrpcclient import Ok, parse

parsed = parse({"jsonrpc": "2.0", "result": "pong", "id": 1})
assert isinstance(parsed, Ok), parsed
print(parsed.result)
Output
pong

Watch out for Any

response.json() in requests, httpx and aiohttp returns Any. Pass that to parse and the result is Any too, so the type checker stops checking: parse(response.json()).result passes mypy and still fails at runtime on an error response. Narrow with isinstance anyway, or annotate the data first:

from typing import Any, Dict

from jsonrpcclient import parse

data: Dict[str, Any] = {"jsonrpc": "2.0", "result": "pong", "id": 1}
parsed = parse(data)  # Ok | Error, so the type checker makes you narrow it

Annotating your own code

jsonrpcclient.responses.Response is the type alias for Ok | Error. Use it for functions that take or return one parsed response. This example passes mypy and pyright in strict mode in CI:

from typing import Any, Dict, List

from jsonrpcclient import Error, Ok, parse
from jsonrpcclient.responses import Response


def describe(response: Response) -> str:
    if isinstance(response, Ok):
        return f"result {response.result!r}"
    return f"error {response.code}: {response.message}"


def result_of(data: Dict[str, Any]) -> Any:
    parsed = parse(data)  # Ok | Error
    if isinstance(parsed, Error):
        raise RuntimeError(parsed.message)
    return parsed.result  # mypy knows parsed is an Ok here


batch: List[Dict[str, Any]] = [
    {"jsonrpc": "2.0", "result": "pong", "id": 1},
    {
        "jsonrpc": "2.0",
        "error": {"code": -32601, "message": "Method not found"},
        "id": 2,
    },
]
for response in parse(batch):  # Iterator[Ok | Error]
    print(describe(response))
print(result_of({"jsonrpc": "2.0", "result": 5, "id": 3}))
Output
result 'pong'
error -32601: Method not found
5

For params, jsonrpcclient.requests.Params is Dict[str, Any] | List[Any] | Tuple[Any, ...]. A string isn't accepted: request("sqrt", "16") is a type error.

The request functions return Dict[str, Any], and the *_json versions return str.