Awesome Open Source
Awesome Open Source


Travis Build Status Requirements Status Apache License

Pure Python implementation of Google Common Expression Language,

The Common Expression Language (CEL) implements common semantics for expression evaluation, enabling different applications to more easily interoperate.

Key Applications

Security policy: organization have complex infrastructure and need common tooling to reason about the system as a whole

Protocols: expressions are a useful data type and require interoperability across programming languages and platforms.

This implementation has minimal dependencies, runs quickly, and can be embedded into Python-based applications. Specifically, the intent is to be part of Cloud Custodian, C7N, as part of the security policy filter.


pip install cel-python

You now have the CEL run-time available to Python-based applications.

Command Line

We can read JSON directly from stdin, making this a bit like jq.

% python -m celpy '.this.from.json * 3 + 3' <<EOF
heredoc> {"this": {"from": {"json": 13}}}
heredoc> EOF

It's also a desk calculator, like expr, but with float values:

% python -m celpy -n '355.0 / 113.0'

It's not as sophistcated as bc. But, yes, this has a tiny advantage over python -c '355/113'. Most notably, the ability to embed Google CEL into other contexts where you don't really want Python's power.

It's also capable of decision-making, like test:

% echo '{"status": 3}' | python -m celpy -sb '.status == 0'
% echo $?

We can provide a -a option to define objects with specific data types. This is particularly helpful for providing protobuf message definitions.

python -m celpy -n --arg x:int=6 --arg y:int=7 'x*y'

If you want to see details of evaluation, use -v.

python -m celpy -v -n '[2, 4, 6].map(n, n/2)'
... a lot of output
[1, 2, 3]


To follow the pattern defined in the Go implementation, there's a multi-step process for compiling a CEL expression to create a runnable "program". This program can then be applied to argument values.

>>> import celpy
>>> cel_source = """
... account.balance >= transaction.withdrawal
... || (account.overdraftProtection
... && account.overdraftLimit >= transaction.withdrawal - account.balance)
... """

>>> env = celpy.Environment()
>>> ast = env.compile(cel_source)
>>> prgm = env.program(ast)

>>> activation = {
...     "account": celpy.json_to_cel({"balance": 500, "overdraftProtection": False}),
...     "transaction": celpy.json_to_cel({"withdrawal": 600})
... }
>>> result = prgm.evaluate(activation)
>>> result

The Python classes are generally based on the object model in These types semantics are slightly different from Python's native semantics. Type coercion is not generally done. Python // truncates toward negative infinity. Go (and CEL) / truncates toward zero.


The parser is based on the grammars used by Go and C++, but processed through Python Lark.



CEL provides a number of runtime errors that are mapped to Python exceptions.

  • no_matching_overload: this function has no overload for the types of the arguments.
  • no_such_field: a map or message does not contain the desired field.
  • return error for overflow: integer arithmetic overflows

There are mapped to Python celpy.evaluation.EvalError exception. The args will have a message similar to the CEL error message, as well as an underlying Python exception.

In principle CEL can pre-check types. However, see Rather than try to pre-check types, we'll rely on Python's implementation.



Code of Conduct

This project adheres to the Open Code of Conduct. By participating, you are expected to honor this code.

Related Awesome Lists
Top Programming Languages
Top Projects

Get A Weekly Email With Trending Projects For These Topics
No Spam. Unsubscribe easily at any time.
Python (822,289
Types (29,995
Cloud Computing (29,149
Rules Engine (487
Cel (7