Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ bazel_dep(name = "bazel_skylib", version = "1.8.2")
# https://registry.bazel.build/modules/cel-cpp
bazel_dep(name = "cel-cpp", version = "0.14.0", repo_name = "com_google_cel_cpp")

# 12/30/2025
_CEL_CPP_COMMIT = "13b249f589ab3e22dee5b384169cb7dd50804b36"
# 03/25/2026
_CEL_CPP_COMMIT = "f6cd0c895e42954475b3734c867e8902557d1b37"

_CEL_CPP_SHA256 = "c7596db4538722e78f9c7f7ae704a15fd48d5e84254d717b5b558c3b1b0169fa"
_CEL_CPP_SHA256 = "8af44a84983f190e30ba4e5064ed5f2a2bbd13988a50b5c75288096636f1548b"

archive_override(
module_name = "cel-cpp",
Expand Down
13 changes: 13 additions & 0 deletions cel_expr_python/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ pybind_extension(
"py_cel_arena.h",
"py_cel_env.cc",
"py_cel_env.h",
"py_cel_env_config.cc",
"py_cel_env_config.h",
"py_cel_env_internal.cc",
"py_cel_env_internal.h",
"py_cel_expression.cc",
Expand Down Expand Up @@ -76,6 +78,8 @@ pybind_extension(
"@com_google_cel_cpp//compiler",
"@com_google_cel_cpp//compiler:compiler_factory",
"@com_google_cel_cpp//compiler:standard_library",
"@com_google_cel_cpp//env:config",
"@com_google_cel_cpp//env:env_yaml",
"@com_google_cel_cpp//extensions/protobuf:runtime_adapter",
"@com_google_cel_cpp//parser:parser_interface",
"@com_google_cel_cpp//runtime",
Expand Down Expand Up @@ -126,3 +130,12 @@ py_test(
"@com_google_protobuf//:protobuf",
],
)

py_test(
name = "cel_env_test",
srcs = ["cel_env_test.py"],
deps = [
":cel",
"@com_google_absl_py//absl/testing:absltest",
],
)
117 changes: 117 additions & 0 deletions cel_expr_python/cel_env_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Tests for Env/Config.

This module contains tests for the `cel.EnvConfig` class, focusing on its
ability to be created from and serialized to YAML format.
"""

from absl.testing import absltest
from cel_expr_python import cel


class CelEnvTest(absltest.TestCase):

def test_env_config_from_and_to_yaml(self):
config = cel.NewEnvConfigFromYaml("""
name: foo
container: test.container
stdlib:
exclude_macros:
- map
- filter
exclude_functions:
- name: "_+_"
extensions:
- name: math
variables:
- name: one
type_name: int
value: 1
functions:
- name: add
overloads:
- id: "add_int_int"
args:
- type_name: int
- type_name: int
return:
type_name: int
""")
yaml = config.to_yaml()
self.assertEqual(
normalize_yaml(yaml),
normalize_yaml("""
name: "foo"
container: "test.container"
extensions:
- name: "math"
stdlib:
exclude_macros:
- "filter"
- "map"
exclude_functions:
- name: "_+_"
variables:
- name: "one"
type_name: "int"
value: 1
functions:
- name: "add"
overloads:
- id: "add_int_int"
args:
- type_name: "int"
- type_name: "int"
return:
type_name: "int"
"""),
)

def test_invalid_yaml(self):
with self.assertRaises(Exception) as e:
cel.NewEnvConfigFromYaml(" invalid yaml")
self.assertIn(
"1:2: Invalid CEL environment config YAML\n"
"| invalid yaml\n"
"| ^",
str(e.exception),
)


def normalize_yaml(yaml: str) -> str:
lines = yaml.split("\n")
indent = -1
unindented_lines = []
for line in lines:
pos = -1
for i, char in enumerate(line):
if char != " " and char != "\t":
pos = i
break
if pos == -1:
# Skip blank lines.
continue
if indent == -1:
indent = pos
if pos >= indent:
unindented_lines.append(line[indent:])
else:
unindented_lines.append(line)
return "\n".join(unindented_lines)


if __name__ == "__main__":
absltest.main()
50 changes: 50 additions & 0 deletions cel_expr_python/py_cel_env_config.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "cel_expr_python/py_cel_env_config.h"

#include <memory>
#include <sstream>
#include <string>

#include "env/env_yaml.h"
#include "cel_expr_python/py_error_status.h"
#include <pybind11/pybind11.h>

namespace cel_python {

namespace py = ::pybind11;

void PyCelEnvConfig::DefinePythonBindings(pybind11::module& m) {
py::class_<PyCelEnvConfig, std::shared_ptr<PyCelEnvConfig>> cel_class(
m, "EnvConfig");
m.def("NewEnvConfigFromYaml", &PyCelEnvConfig::FromYaml, py::arg("yaml"));

cel_class.def("to_yaml", &PyCelEnvConfig::ToYaml);
}

PyCelEnvConfig PyCelEnvConfig::FromYaml(std::string yaml) {
PyCelEnvConfig config;
config.config_ = ThrowIfError(cel::EnvConfigFromYaml(yaml));
return config;
}

std::string PyCelEnvConfig::ToYaml() const {
std::stringstream ss;
cel::EnvConfigToYaml(config_, ss);
return ss.str();
}

} // namespace cel_python
39 changes: 39 additions & 0 deletions cel_expr_python/py_cel_env_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef THIRD_PARTY_CEL_PYTHON_PY_CEL_ENV_CONFIG_H_
#define THIRD_PARTY_CEL_PYTHON_PY_CEL_ENV_CONFIG_H_

#include <string>

#include "env/config.h"
#include <pybind11/pybind11.h>

namespace cel_python {

class PyCelEnvConfig {
public:
static void DefinePythonBindings(pybind11::module& m);

static PyCelEnvConfig FromYaml(std::string yaml);
std::string ToYaml() const;

private:
cel::Config config_;
};

} // namespace cel_python

#endif // THIRD_PARTY_CEL_PYTHON_PY_CEL_ENV_CONFIG_H_
2 changes: 2 additions & 0 deletions cel_expr_python/py_cel_module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "cel_expr_python/py_cel_activation.h"
#include "cel_expr_python/py_cel_arena.h"
#include "cel_expr_python/py_cel_env.h"
#include "cel_expr_python/py_cel_env_config.h"
#include "cel_expr_python/py_cel_expression.h"
#include "cel_expr_python/py_cel_function.h"
#include "cel_expr_python/py_cel_function_decl.h"
Expand All @@ -38,6 +39,7 @@ PYBIND11_MODULE(cel, m) {
PyCelFunctionDecl::DefinePythonBindings(m);
PyCelPythonExtension::DefinePythonBindings(m);
PyCelFunction::DefinePythonBindings(m);
PyCelEnvConfig::DefinePythonBindings(m);
PyCelEnv::DefinePythonBindings(m);
}

Expand Down
Loading