Skip to content

Commit 7122697

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 7122697

16 files changed

Lines changed: 239 additions & 146 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: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
from absl.testing import absltest
2222
from cel_expr_python import cel
23+
from cel_expr_python.ext import ext_math
2324
from cel.expr.conformance.proto2 import test_all_types_pb2 as test_all_types_pb
2425

2526

@@ -91,6 +92,18 @@ def test_invalid_yaml(self):
9192
str(e.exception),
9293
)
9394

95+
def test_config_export_container(self):
96+
env = cel.NewEnv(
97+
container="test.container"
98+
)
99+
yaml = env.config().to_yaml()
100+
self.assertEqual(
101+
normalize_yaml(yaml),
102+
normalize_yaml("""
103+
container: "test.container"
104+
"""),
105+
)
106+
94107
def test_config_export_variables(self):
95108
config = cel.NewEnv(
96109
variables={
@@ -236,6 +249,75 @@ def test_config_variable_types(self):
236249
self.assertEqual(res.type(), cel.Type.INT)
237250
self.assertEqual(res.value(), 42)
238251

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

240322
def normalize_yaml(yaml: str) -> str:
241323
lines = yaml.split("\n")

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,

cel_expr_python/ext/ext_proto.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/proto_ext.h"
1817
#include "cel_expr_python/cel_extension.h"
19-
#include "google/protobuf/descriptor.h"
2018

2119
namespace cel_python {
2220

2321
class ExtProto : public CelExtension {
2422
public:
2523
explicit ExtProto() : CelExtension("cel.lib.ext.proto") {}
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::ProtoExtCompilerLibrary());
25+
cel::CompilerLibrary GetCompilerLibrary() override {
26+
return cel::extensions::ProtoExtCompilerLibrary();
3227
}
3328
};
3429

0 commit comments

Comments
 (0)