API¶
This part of the documentation covers all the interfaces of regopy.
Interpreter¶
- class regopy.Interpreter(v1_compatible=False)¶
Pythonic interface to the rego-cpp interpreter.
This wraps the Rego C API, and handles passing calls to the C API and converting the results to Python types.
Examples
>>> from regopy import Interpreter >>> rego = Interpreter() >>> print(rego.query("x=5;y=x + (2 - 4 * 0.25) * -3 + 7.4")) {"bindings":{"x":5, "y":9.4}}
>>> input = { ... "a": 10, ... "b": "20", ... "c": 30.0, ... "d": True ... } >>> data0 = { ... "one": { ... "bar": "Foo", ... "baz": 5, ... "be": True, ... "bop": 23.4 ... }, ... "two": { ... "bar": "Bar", ... "baz": 12.3, ... "be": False, ... "bop": 42 ... } ... } >>> data1 = { ... "three": { ... "bar": "Baz", ... "baz": 15, ... "be": True, ... "bop": 4.23 ... } ... } >>> module = ''' ... package objects ... ... rect := {`width`: 2, "height": 4} ... cube := {"width": 3, `height`: 4, "depth": 5} ... a := 42 ... b := false ... c := null ... d := {"a": a, "x": [b, c]} ... index := 1 ... shapes := [rect, cube] ... names := ["prod", `smoke1`, "dev"] ... sites := [{"name": "prod"}, {"name": names[index]}, {"name": "dev"}] ... e := { ... a: "foo", ... "three": c, ... names[2]: b, ... "four": d, ... } ... f := e["dev"] ... ''' >>> rego.set_input(input) >>> rego.add_data(data0) >>> rego.add_data(data1) >>> rego.add_module("objects", module) >>> print(rego.query("x=[data.one, input.b, data.objects.sites[1]]")) {"bindings":{"x":[{"bar":"Foo", "baz":5, "be":true, "bop":23.4}, "20", {"name":"smoke1"}]}}
- add_data(data)¶
Adds data (i.e. a base document) to the interpreter.
The data should be provided as single, JSON-encodable Python object.
- Parameters:
data (Any) – The data.
- Raises:
RegoError – If an error occurs in the Rego interpreter.
See also
- add_data_json(json)¶
Adds data (i.e. a base document) to the interpreter.
The data should be provided as single JSON-encoded object.
- Parameters:
json (str) – The data JSON.
- Raises:
RegoError – If an error occurs in the Rego interpreter.
Example
>>> from regopy import Interpreter >>> rego = Interpreter() >>> data = ''' ... { ... "one": { ... "bar": "Foo", ... "baz": 5, ... "be": true, ... "bop": 23.4 ... }, ... "two": { ... "bar": "Bar", ... "baz": 12.3, ... "be": false, ... "bop": 42 ... } ... } ... ''' >>> rego.add_data_json(data) >>> output = rego.query("data.one.bar") >>> print(output) {"expressions":["Foo"]}
- add_module(name, source)¶
Adds a module (i.e. a virtual document) to the interpreter.
- Parameters:
name (str) – The module name.
source (str) – The module source.
- Raises:
RegoError – If an error occurs in the Rego interpreter.
Example
>>> from regopy import Interpreter >>> module = ''' ... package scalars ... ... greeting := "Hello" ... max_height := 42 ... pi := 3.14159 ... allowed := true ... location := null ... ''' >>> rego = Interpreter() >>> rego.add_module("scalars", module) >>> output = rego.query("data.scalars.greeting") >>> print(output) {"expressions":["Hello"]}
- property debug_enabled: bool¶
Whether debug mode is enabled.
When debug mode is enabled, the Rego interpreter will output extensive debugging information about the compliation process, including intermediary ASTs and the generated bytecode. This is mostly useful for debugging the Rego compiler itself, and may not be as useful for debugging Rego policies.
- query(query)¶
Performs a query against the current set of base and virtual documents.
While the Rego interpreter can be used to perform simple queries, in most cases users will want to load one or more base documents (using
add_data()
oradd_data_json()
) and one or more Rego modules (usingadd_module()
oradd_module_file()
). Then, multiple queries can be performed by providing an input (usingset_input()
orset_input_json()
) and then calling this method.- Parameters:
query (str) – The query.
- Returns:
The query result.
- Return type:
- Raises:
RegoError – If an error occurs in the Rego interpreter.
Examples
>>> from regopy import Interpreter >>> input0 = {"a": 10} >>> input1 = {"a": 4} >>> input2 = {"a": 7} >>> multi = ''' ... package multi ... ... default a := 0 ... ... a := val { ... input.a > 0 ... input.a < 10 ... input.a % 2 == 1 ... val := input.a * 10 ... } { ... input.a > 0 ... input.a < 10 ... input.a % 2 == 0 ... val := input.a * 10 + 1 ... } ... ... a := input.a / 10 { ... input.a >= 10 ... } ... ''' >>> rego = Interpreter() >>> rego.add_module("multi", multi) >>> rego.set_input(input0) >>> output = rego.query("data.multi.a") >>> print(output) {"expressions":[1]} >>> rego.set_input(input1) >>> output = rego.query("data.multi.a") >>> print(output) {"expressions":[41]} >>> rego.set_input(input2) >>> output = rego.query("data.multi.a") >>> print(output) {"expressions":[70]}
- set_debug_path(path)¶
Sets the path to the directory where this will write debug AST files.
This is only useful when debug mode is enabled.
- Parameters:
path (str) – The path to the directory where this will write debug AST files.
- set_input(value)¶
Sets the input document of the interpreter.
This can be called several times during the lifetime of the interpreter. The value must be JSON encodable.
- Parameters:
value (Any) – The input value.
- Raises:
RegoError – If an error occurs in the Rego interpreter.
See also
- set_input_json(json)¶
Sets the input document of the interpreter.
This can be called several times during the lifetime of the interpreter. The input should be provided as single JSON-encoded value.
- Parameters:
json (str) – The input JSON.
- Raises:
RegoError – If an error occurs in the Rego interpreter.
Example
>>> from regopy import Interpreter >>> input = ''' ... { ... "a": 10, ... "b": "20", ... "c": 30.0, ... "d": true ... } ... ''' >>> rego = Interpreter() >>> rego.set_input_json(input) >>> output = rego.query("input.a") >>> print(output) {"expressions":[10]}
- set_input_term(term)¶
Sets the input term of the interpreter.
This can be called several times during the lifetime of the interpreter.
- Parameters:
term (str) – The input term.
- Raises:
RegoError – If an error occurs in the Rego interpreter.
Example
>>> from regopy import Interpreter >>> input = ''' ... { ... "a": 10, ... "b": "20", ... "c": 30.0, ... "d": true ... } ... ''' >>> rego = Interpreter() >>> rego.set_input_json(input) >>> output = rego.query("input.a") >>> print(output) {"expressions":[10]}
- property strict_built_in_errors: bool¶
Whether the interpreter will forward errors thrown by the built-ins.
By default, the Rego interpreter will catch errors thrown by the built-ins and return them as an Undefined result. When this is enabled, the interpreter will instead forward the error to the caller.
- property well_formed_checks_enabled: bool¶
Whether the Rego interpreter will perform well-formedness checks.
When enabled, the Rego interpreter will perform well-formedness checks on the AST during each pass of the compiler.
Output¶
- class regopy.Output(impl)¶
Interface for the Rego output.
Outputs can either be examined as strings, or inspected using Rego Nodes. It is also possible to extract bindings for specific variables.
Examples
>>> from regopy import Interpreter >>> rego = Interpreter() >>> output = rego.query("x=5;y=x + (2 - 4 * 0.25) * -3 + 7.4;2 * 5") >>> print(output) {"expressions":[10], "bindings":{"x":5, "y":9.4}}
>>> x = output.binding("x") >>> print(x.json()) 5
- binding(name, index=0)¶
Attempts to return the binding for the given variable name.
- Parameters:
name (str) – The name of the variable to return.
index (int, optional) – The index of the binding to return.
- Returns:
The binding for the given variable name.
- Return type:
- Raises:
ValueError – If the variable is not bound.
- expressions(index=0)¶
Returns the output terms at the given index.
- Parameters:
index (int, optional) – The index of the term to return.
- Returns:
A node contains a list of node objects
- Return type:
- ok()¶
Returns whether the output is ok.
The output of a successful query will always be a Node. However, if there was an error that arose with the Rego engine, then this Node will be of kind NodeKind.ErrorSeq and contain one or more errors. This method gives a quick way, without inspecting the result node, of finding whether it is ok.
- Return type:
bool
Node¶
- class regopy.Node(impl)¶
Interface for the Rego Node.
Rego Nodes are the basic building blocks of a Rego result. They exist in a tree structure. Each node has a kind, which is one of the variants of [NodeKind]. Each node also has zero or more children, which are also nodes.
Examples: >>> from regopy import Interpreter >>> rego = Interpreter() >>> output = rego.query(‘x={“a”: 10, “b”: “20”, “c”: [30.0, 60], “d”: true, “e”: null}’) >>> x = output.binding(“x”) >>> print(“x =”, x.json()) x = {“a”:10, “b”:”20”, “c”:[30, 60], “d”:true, “e”:null}
>>> print("x['a'] =", x["a"].value) x['a'] = 10
>>> print("x['b'] =", x["b"].value) x['b'] = "20"
>>> print("x['c'][0] =", x["c"][0].value) x['c'][0] = 30.0
>>> print("x['c'][1] =", x["c"][1].value) x['c'][1] = 60
>>> print("x['d'] =", x["d"].value) x['d'] = True
>>> print("x['e'] =", x["e"].value) x['e'] = None
- index(index)¶
Returns the node at an index of an array.
- Returns:
The child node.
- Return type:
- Raises:
IndexError – If the index is out of bounds.
TypeError – If the node is not an array.
- json()¶
Returns the node as a JSON string.
- Return type:
str
- property kind_name: str¶
Returns a human-readable string representation of the node kind.
- lookup(key)¶
Returns the child node for the given key.
If this is of kind Object or Set, then the key must be a string.
- Returns:
The child node.
- Return type:
- Raises:
KeyError – If the key is not found.
TypeError – If the node does not support lookup
- property value: str | int | float | bool | None¶
Returns the node value.
If the node has a singular value (i.e is a Scalar or a Term containing a scalar) then this will return that value. Otherwise it will raise a RegoError.
- Returns:
The node value.
- Return type:
Union[str, int, float, bool, None]
- Raises:
RegoError – If the node does not have a singular value.
Examples
>>> from regopy import Interpreter >>> rego = Interpreter() >>> output = rego.query('x=10; y="20"; z=true') >>> x = output.binding("x") >>> print("x =", x.value) x = 10
>>> y = output.binding("y") >>> print("y =", y.value) y = "20"
>>> z = output.binding("z") >>> print("z =", z.value) z = True
- enum regopy.NodeKind(value)¶
Enumeration of node types.
- Member Type:
int
Valid values are as follows:
- Binding = <NodeKind.Binding: 1000>¶
- Var = <NodeKind.Var: 1001>¶
- Term = <NodeKind.Term: 1002>¶
- Scalar = <NodeKind.Scalar: 1003>¶
- Array = <NodeKind.Array: 1004>¶
- Set = <NodeKind.Set: 1005>¶
- Object = <NodeKind.Object: 1006>¶
- ObjectItem = <NodeKind.ObjectItem: 1007>¶
- Int = <NodeKind.Int: 1008>¶
- Float = <NodeKind.Float: 1009>¶
- String = <NodeKind.String: 1010>¶
- Boolean = <NodeKind.Boolean: 1011>¶
- Null = <NodeKind.Null: 1013>¶
- Undefined = <NodeKind.Undefined: 1014>¶
- Terms = <NodeKind.Terms: 1015>¶
- Bindings = <NodeKind.Bindings: 1016>¶
- Results = <NodeKind.Results: 1017>¶
- Result = <NodeKind.Result: 1018>¶
- Error = <NodeKind.Error: 1800>¶
- ErrorMessage = <NodeKind.ErrorMessage: 1801>¶
- ErrorAst = <NodeKind.ErrorAst: 1802>¶
- ErrorCode = <NodeKind.ErrorCode: 1803>¶
- ErrorSeq = <NodeKind.ErrorSeq: 1804>¶
- Internal = <NodeKind.Internal: 1999>¶