Skip to content

Oracle

Provide the Sage-backed daemon: its protocol entry point and the exact building blocks of its methods.

Importing this package imports SageMath.

answer_request(line)

Answer one JSON request line with one response object, never raising.

Parameters:

Name Type Description Default
line str

A JSON object with id, method and optional params.

required

Returns:

Type Description
JsonObject

The response: {"id", "result", "veriphy"} on success, {"id", "error", "veriphy"} on failure.

Examples:

>>> answer_request('{"id": 1, "method": "ping"}')['result']['ok']
True
>>> answer_request('{"id": 2, "method": "nosuch"}')['error'].startswith("unknown method 'nosuch'")
True
Source code in src/veriphy/oracle/_protocol.py
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
def answer_request(line: str) -> JsonObject:
    """Answer one JSON request line with one response object, never raising.

    Args:
        line: A JSON object with `id`, `method` and optional `params`.

    Returns:
        The response: `{"id", "result", "veriphy"}` on success, `{"id", "error", "veriphy"}` on failure.

    Examples:
        >>> answer_request('{"id": 1, "method": "ping"}')['result']['ok']
        True
        >>> answer_request('{"id": 2, "method": "nosuch"}')['error'].startswith("unknown method 'nosuch'")
        True
    """
    req_id: JsonValue = None
    try:
        req = json.loads(line)
        req_id = req.get('id')
        name = req.get('method')
        if name not in METHODS:
            return _respond(req_id, 'error', f"unknown method '{name}' (known: {sorted(METHODS)})")
        return _respond(req_id, 'result', METHODS[name](req.get('params') or {}))
    except MethodError as exc:
        return _respond(req_id, 'error', str(exc))
    except (json.JSONDecodeError, AttributeError) as exc:
        return _respond(req_id, 'error', f'{type(exc).__name__}: {exc}')

encode(x, *, advisory=False, depth=0)

Encode a method result exactly as JSON.

Rationals and integers of Sage become "n" or "n/d" strings, polynomials become term lists, and containers are encoded element by element. Python integers stay integers, since they are structural (exponents, counts).

Parameters:

Name Type Description Default
x object

The value to encode.

required
advisory bool

Whether the result is advisory. Advisory results may carry floats and fall back to str.

False
depth int

The current nesting depth.

0

Returns:

Type Description
JsonValue

The JSON value.

Raises:

Type Description
EncodingError

If a certificate result holds a float, an opaque object, or nests too deeply.

Examples:

>>> from sage.all import QQ
>>> encode({'m': [QQ(-3) / 2, 5]})
{'m': ['-3/2', 5]}
Source code in src/veriphy/oracle/_encoding.py
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
58
59
60
61
62
63
def encode(x: object, *, advisory: bool = False, depth: int = 0) -> JsonValue:
    """Encode a method result exactly as JSON.

    Rationals and integers of Sage become `"n"` or `"n/d"` strings, polynomials become term lists, and containers are
    encoded element by element. Python integers stay integers, since they are structural (exponents, counts).

    Args:
        x: The value to encode.
        advisory: Whether the result is advisory. Advisory results may carry floats and fall back to `str`.
        depth: The current nesting depth.

    Returns:
        The JSON value.

    Raises:
        EncodingError: If a certificate result holds a float, an opaque object, or nests too deeply.

    Examples:
        >>> from sage.all import QQ
        >>> encode({'m': [QQ(-3) / 2, 5]})
        {'m': ['-3/2', 5]}
    """
    if isinstance(x, float) and not advisory:
        message = f'floating-point value {x} in a certificate result'
        raise EncodingError(message)
    if x is None or isinstance(x, bool | str | int | float):
        return x
    if isinstance(x, list | tuple | dict) and depth <= MAX_DEPTH:
        return _encode_container(x, advisory=advisory, depth=depth)
    if isinstance(x, MPolynomial | Polynomial):
        return _encode_polynomial(x)
    if (isinstance(x, Element) and x.parent() in (QQ, ZZ)) or advisory:
        return str(x)
    message = f'cannot encode {type(x).__name__} exactly'
    raise EncodingError(message)