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()

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() or add_data_json()) and one or more Rego modules (using add_module() or add_module_file()). Then, multiple queries can be performed by providing an input (using set_input() or set_input_json()) and then calling this method.

Parameters:

query (str) – The query.

Returns:

The query result.

Return type:

Output

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()

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:

Node

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:

Node

node()

Returns the root node of the output.

Return type:

Node

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
at(index)

Returns the child node at the given index.

Return type:

Node

index(index)

Returns the node at an index of an array.

Returns:

The child node.

Return type:

Node

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: NodeKind

Returns the node type.

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:

Node

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>

Logging

enum regopy.LogLevel(value)
Member Type:

int

Valid values are as follows:

NONE = <LogLevel.NONE: 0>
ERROR = <LogLevel.ERROR: 1>
OUTPUT = <LogLevel.OUTPUT: 2>
WARN = <LogLevel.WARN: 3>
INFO = <LogLevel.INFO: 4>
DEBUG = <LogLevel.DEBUG: 5>
TRACE = <LogLevel.TRACE: 6>
regopy.set_log_level(level)

Sets the log level.

Parameters:

level (LogLevel) – The log level.