Skip to content

Commit 5411725

Browse files
dmitriplotnikovcopybara-github
authored andcommitted
Store CEL container within cel::Config
This change simplifies the internal representation and ensures the container is part of the exported environment configuration. PiperOrigin-RevId: 893173014
1 parent 1ec5a73 commit 5411725

16 files changed

Lines changed: 242 additions & 165 deletions

MODULE.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ bazel_dep(name = "bazel_skylib", version = "1.8.2")
1414
# https://registry.bazel.build/modules/cel-cpp
1515
bazel_dep(name = "cel-cpp", version = "0.14.0", repo_name = "com_google_cel_cpp")
1616

17-
# 03/30/2026
17+
# 04/01/2026
1818
_CEL_CPP_COMMIT = "5a3463337cf2a9b90b53833af2bbc1f35da90d64"
1919

2020
_CEL_CPP_SHA256 = "299be398d1495340eb92da31f9a0667e1351479752e8a567ac31c385e4aea73c"

README.md

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -234,36 +234,34 @@ expr = cel_env.compile("my_func(1)")
234234

235235
To define a custom extension in C++, define a class extending
236236
`cel_python::CelExtension`. There are two methods you will need to implement:
237-
`ConfigureCompiler` and `ConfigureRuntime`. The implementations of these methods
238-
use the same API as extensions written for the C++ CEL runtime. In fact,
237+
`GetCompilerLibrary` and `ConfigureRuntime`. The implementations of these
238+
methods use the same API as extensions written for the C++ CEL runtime. In fact,
239239
extensions written for the C++ runtime can be used unchanged with
240240
cel-expr-python - you would just need to write a trivial wrapper class invoking
241241
the registration functions defined by the C++ extension.
242242

243-
```cpp
244-
absl::Status ConfigureCompiler(
245-
cel::CompilerBuilder& compiler_builder,
246-
const proto2::DescriptorPool& descriptor_pool);
247-
```
248243
This method adds extension function definitions to the provided
249244
`CompilerBuilder`, for example:
250245

251246
```cpp
252-
absl::Status ConfigureCompiler(
253-
cel::CompilerBuilder& compiler_builder,
254-
const proto2::DescriptorPool& descriptor_pool) {
255-
CEL_PYTHON_ASSIGN_OR_RETURN(
256-
auto func_translate,
257-
cel::MakeFunctionDecl("translate",
258-
cel::MakeMemberOverloadDecl("translate_inst",
259-
/*return_type=*/cel::StringType(),
260-
/*target=*/cel::StringType(),
261-
/*from_lang=*/cel::StringType(),
262-
/*to_lang=*/cel::StringType())));
263-
CEL_PYTHON_RETURN_IF_ERROR(
264-
compiler_builder.GetCheckerBuilder().AddFunction(func_translate));
265-
return absl::OkStatus();
266-
}
247+
cel::CompilerLibrary GetCompilerLibrary() {
248+
return cel::CompilerLibrary(
249+
"translate-ext",
250+
[](cel::TypeCheckerBuilder& checker_builder) -> absl::Status {
251+
CEL_PYTHON_ASSIGN_OR_RETURN(
252+
auto func_translate,
253+
cel::MakeFunctionDecl(
254+
"translate",
255+
cel::MakeMemberOverloadDecl("translate_inst",
256+
/*return_type=*/cel::StringType(),
257+
/*target=*/cel::StringType(),
258+
/*from_lang=*/cel::StringType(),
259+
/*to_lang=*/cel::StringType())));
260+
CEL_PYTHON_RETURN_IF_ERROR(
261+
checker_builder.AddFunction(func_translate));
262+
return absl::OkStatus();
263+
});
264+
}
267265
```
268266
269267
The other method registers the actual implementation

cel_expr_python/BUILD

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ pybind_extension(
6363
"@com_google_absl//absl/types:optional",
6464
"@com_google_absl//absl/types:span",
6565
"@com_google_cel_cpp//checker:type_checker_builder",
66+
"@com_google_cel_cpp//checker:type_checker_builder_factory",
6667
"@com_google_cel_cpp//checker:validation_result",
6768
"@com_google_cel_cpp//common:ast",
6869
"@com_google_cel_cpp//common:ast_proto",
@@ -78,8 +79,13 @@ pybind_extension(
7879
"@com_google_cel_cpp//compiler",
7980
"@com_google_cel_cpp//env",
8081
"@com_google_cel_cpp//env:config",
82+
"@com_google_cel_cpp//env:env_runtime",
83+
"@com_google_cel_cpp//env:env_std_extensions",
8184
"@com_google_cel_cpp//env:env_yaml",
85+
"@com_google_cel_cpp//env:runtime_std_extensions",
8286
"@com_google_cel_cpp//extensions/protobuf:runtime_adapter",
87+
"@com_google_cel_cpp//parser",
88+
"@com_google_cel_cpp//parser:options",
8389
"@com_google_cel_cpp//parser:parser_interface",
8490
"@com_google_cel_cpp//runtime",
8591
"@com_google_cel_cpp//runtime:activation",
@@ -88,7 +94,6 @@ pybind_extension(
8894
"@com_google_cel_cpp//runtime:reference_resolver",
8995
"@com_google_cel_cpp//runtime:runtime_builder",
9096
"@com_google_cel_cpp//runtime:runtime_options",
91-
"@com_google_cel_cpp//runtime:standard_runtime_builder_factory",
9297
"@com_google_cel_spec//proto/cel/expr:checked_cc_proto",
9398
"@com_google_cel_spec//proto/cel/expr:syntax_cc_proto",
9499
"@com_google_protobuf//:protobuf",
@@ -135,6 +140,7 @@ py_test(
135140
srcs = ["cel_env_test.py"],
136141
deps = [
137142
":cel",
143+
"//cel_expr_python/ext:ext_math",
138144
"//testing:proto2_test_all_types_py_pb2",
139145
"@com_google_absl_py//absl/testing:absltest",
140146
],

cel_expr_python/cel_env_test.py

Lines changed: 85 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@
1818
ability to be created from and serialized to YAML format.
1919
"""
2020

21+
import textwrap
22+
2123
from absl.testing import absltest
2224
from cel_expr_python import cel
25+
from cel_expr_python.ext import ext_math
2326
from cel.expr.conformance.proto2 import test_all_types_pb2 as test_all_types_pb
2427

2528

@@ -91,6 +94,18 @@ def test_invalid_yaml(self):
9194
str(e.exception),
9295
)
9396

97+
def test_config_export_container(self):
98+
env = cel.NewEnv(
99+
container="test.container"
100+
)
101+
yaml = env.config().to_yaml()
102+
self.assertEqual(
103+
normalize_yaml(yaml),
104+
normalize_yaml("""
105+
container: "test.container"
106+
"""),
107+
)
108+
94109
def test_config_export_variables(self):
95110
config = cel.NewEnv(
96111
variables={
@@ -236,27 +251,78 @@ def test_config_variable_types(self):
236251
self.assertEqual(res.type(), cel.Type.INT)
237252
self.assertEqual(res.value(), 42)
238253

254+
def test_config_extensions(self):
255+
config = cel.NewEnvConfigFromYaml("""
256+
extensions:
257+
- name: math
258+
- name: strings
259+
""")
260+
env = cel.NewEnv(
261+
config=config,
262+
extensions=[TestCelExtension()],
263+
)
264+
yaml = env.config().to_yaml()
265+
self.assertEqual(
266+
normalize_yaml(yaml),
267+
normalize_yaml("""
268+
extensions:
269+
- name: "math"
270+
- name: "strings"
271+
- name: "test_cel_extension"
272+
"""),
273+
)
274+
res = env.compile("'%.4f'.format([math.sqrt(2)])").eval()
275+
self.assertEqual(res.value(), "1.4142")
276+
res = env.compile("hello('World')").eval()
277+
self.assertEqual(res.value(), "Hello, World!")
278+
279+
def test_config_extensions_override(self):
280+
# TODO(b/498655870): add assertion based on extension aliases once
281+
# supported.
282+
config = cel.NewEnvConfigFromYaml("""
283+
extensions:
284+
- name: cel.lib.ext.math
285+
version: 0
286+
- name: cel.lib.ext.strings
287+
""")
288+
with self.assertRaises(Exception) as e:
289+
cel.NewEnv(
290+
config=config,
291+
extensions=[ext_math.ExtMath()],
292+
)
293+
self.assertIn(
294+
"Extension 'cel.lib.ext.math' version 0 is already included. Cannot"
295+
" also include version 'latest'",
296+
str(e.exception),
297+
)
298+
299+
300+
class TestCelExtension(cel.CelExtension):
301+
"""An example CEL extension for testing."""
302+
303+
def __init__(self):
304+
super().__init__(
305+
"test_cel_extension",
306+
functions=[
307+
cel.FunctionDecl(
308+
"hello",
309+
[
310+
cel.Overload(
311+
"hello(string)",
312+
return_type=cel.Type.STRING,
313+
parameters=[
314+
cel.Type.STRING,
315+
],
316+
impl=lambda arg: f"Hello, {arg}!",
317+
)
318+
],
319+
),
320+
],
321+
)
322+
239323

240324
def normalize_yaml(yaml: str) -> str:
241-
lines = yaml.split("\n")
242-
indent = -1
243-
unindented_lines = []
244-
for line in lines:
245-
pos = -1
246-
for i, char in enumerate(line):
247-
if char != " " and char != "\t":
248-
pos = i
249-
break
250-
if pos == -1:
251-
# Skip blank lines.
252-
continue
253-
if indent == -1:
254-
indent = pos
255-
if pos >= indent:
256-
unindented_lines.append(line[indent:])
257-
else:
258-
unindented_lines.append(line)
259-
return "\n".join(unindented_lines)
325+
return textwrap.dedent(yaml).strip()
260326

261327

262328
if __name__ == "__main__":

cel_expr_python/cel_extension.h

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
#include "compiler/compiler.h"
2525
#include "runtime/runtime_builder.h"
2626
#include "runtime/runtime_options.h"
27-
#include "google/protobuf/descriptor.h"
2827

2928
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS)
3029
// This include causes many issues if included in C++ environments that don't
@@ -42,10 +41,8 @@ class CelExtension {
4241
explicit CelExtension(std::string name) : name_(std::move(name)) {};
4342
virtual ~CelExtension() = default;
4443

45-
virtual absl::Status ConfigureCompiler(
46-
cel::CompilerBuilder& compiler_builder,
47-
const google::protobuf::DescriptorPool& descriptor_pool) {
48-
return absl::OkStatus();
44+
virtual cel::CompilerLibrary GetCompilerLibrary() {
45+
return cel::CompilerLibrary(name_, nullptr, nullptr);
4946
}
5047

5148
virtual absl::Status ConfigureRuntime(cel::RuntimeBuilder& runtime_builder,
@@ -76,11 +73,11 @@ class CelExtension {
7673
//
7774
// CEL_EXTENSION_MODULE(sample_cel_ext, SampleCelExtension);
7875
//
79-
#define CEL_EXTENSION_MODULE(module_name, class_name) \
80-
PYBIND11_MODULE(module_name, m) { \
81-
pybind11::module_::import(CEL_MODULE_NAME); \
76+
#define CEL_EXTENSION_MODULE(module_name, class_name) \
77+
PYBIND11_MODULE(module_name, m) { \
78+
pybind11::module_::import(CEL_MODULE_NAME); \
8279
pybind11::class_<class_name, cel_python::CelExtension>(m, #class_name) \
83-
.def(pybind11::init<>()); \
80+
.def(pybind11::init<>()); \
8481
}
8582

8683
} // namespace cel_python

cel_expr_python/ext/ext_bindings.cc

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,18 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
#include "absl/status/status.h"
1615
#include "compiler/compiler.h"
1716
#include "extensions/bindings_ext.h"
1817
#include "cel_expr_python/cel_extension.h"
19-
#include "google/protobuf/descriptor.h"
2018

2119
namespace cel_python {
2220

2321
class ExtBindings : public CelExtension {
2422
public:
2523
explicit ExtBindings() : CelExtension("cel.lib.ext.cel.bindings") {}
2624

27-
absl::Status ConfigureCompiler(
28-
cel::CompilerBuilder& compiler_builder,
29-
const google::protobuf::DescriptorPool& descriptor_pool) override {
30-
return compiler_builder.AddLibrary(
31-
cel::extensions::BindingsCompilerLibrary());
25+
cel::CompilerLibrary GetCompilerLibrary() override {
26+
return cel::extensions::BindingsCompilerLibrary();
3227
}
3328
};
3429

cel_expr_python/ext/ext_encoders.cc

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,20 @@
1313
// limitations under the License.
1414

1515
#include "absl/status/status.h"
16-
#include "checker/type_checker_builder.h"
1716
#include "compiler/compiler.h"
1817
#include "extensions/encoders.h"
1918
#include "runtime/runtime_builder.h"
2019
#include "runtime/runtime_options.h"
2120
#include "cel_expr_python/cel_extension.h"
22-
#include "google/protobuf/descriptor.h"
2321

2422
namespace cel_python {
2523

2624
class ExtEncoders : public CelExtension {
2725
public:
2826
explicit ExtEncoders() : CelExtension("cel.lib.ext.encoders") {}
2927

30-
absl::Status ConfigureCompiler(
31-
cel::CompilerBuilder& compiler_builder,
32-
const google::protobuf::DescriptorPool& descriptor_pool) override {
33-
return compiler_builder.GetCheckerBuilder().AddLibrary(
34-
cel::extensions::EncodersCheckerLibrary());
28+
cel::CompilerLibrary GetCompilerLibrary() override {
29+
return cel::extensions::EncodersCompilerLibrary();
3530
}
3631

3732
absl::Status ConfigureRuntime(cel::RuntimeBuilder& runtime_builder,

cel_expr_python/ext/ext_math.cc

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,21 @@
1919
#include "runtime/runtime_builder.h"
2020
#include "runtime/runtime_options.h"
2121
#include "cel_expr_python/cel_extension.h"
22-
#include "cel_expr_python/status_macros.h"
23-
#include "google/protobuf/descriptor.h"
2422

2523
namespace cel_python {
2624

2725
class ExtMath : public CelExtension {
2826
public:
2927
explicit ExtMath() : CelExtension("cel.lib.ext.math") {}
3028

31-
absl::Status ConfigureCompiler(
32-
cel::CompilerBuilder& compiler_builder,
33-
const google::protobuf::DescriptorPool& descriptor_pool) override {
34-
return compiler_builder.AddLibrary(cel::extensions::MathCompilerLibrary());
29+
cel::CompilerLibrary GetCompilerLibrary() override {
30+
return cel::extensions::MathCompilerLibrary();
3531
}
3632

3733
absl::Status ConfigureRuntime(cel::RuntimeBuilder& runtime_builder,
3834
const cel::RuntimeOptions& opts) override {
39-
CEL_PYTHON_RETURN_IF_ERROR(cel::extensions::RegisterMathExtensionFunctions(
40-
runtime_builder.function_registry(), opts));
41-
return absl::OkStatus();
35+
return cel::extensions::RegisterMathExtensionFunctions(
36+
runtime_builder.function_registry(), opts);
4237
}
4338
};
4439

cel_expr_python/ext/ext_optional.cc

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,15 @@
1919
#include "runtime/runtime_builder.h"
2020
#include "runtime/runtime_options.h"
2121
#include "cel_expr_python/cel_extension.h"
22-
#include "google/protobuf/descriptor.h"
2322

2423
namespace cel_python {
2524

2625
class ExtOptional : public CelExtension {
2726
public:
28-
explicit ExtOptional() : CelExtension("cel.lib.optional") {}
27+
explicit ExtOptional() : CelExtension("optional") {}
2928

30-
absl::Status ConfigureCompiler(
31-
cel::CompilerBuilder& compiler_builder,
32-
const google::protobuf::DescriptorPool& descriptor_pool) override {
33-
return compiler_builder.AddLibrary(cel::OptionalCompilerLibrary());
29+
cel::CompilerLibrary GetCompilerLibrary() override {
30+
return cel::OptionalCompilerLibrary();
3431
}
3532

3633
absl::Status ConfigureRuntime(cel::RuntimeBuilder& runtime_builder,

0 commit comments

Comments
 (0)