Skip to content

Commit db8f49e

Browse files
dmitriplotnikovcopybara-github
authored andcommitted
Make extensions reusable across different environments
PiperOrigin-RevId: 852967383
1 parent a24efe8 commit db8f49e

8 files changed

Lines changed: 34 additions & 41 deletions

BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ pybind_extension(
8181
"@com_google_cel_cpp//parser:parser_interface",
8282
"@com_google_cel_cpp//runtime",
8383
"@com_google_cel_cpp//runtime:activation",
84+
"@com_google_cel_cpp//runtime:embedder_context",
8485
"@com_google_cel_cpp//runtime:function",
8586
"@com_google_cel_cpp//runtime:reference_resolver",
8687
"@com_google_cel_cpp//runtime:runtime_builder",

py_cel_activation.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ namespace cel_python {
3737

3838
namespace py = ::pybind11;
3939

40+
static const cel::FunctionDescriptorOptions kFunctionDescriptorOptions = {
41+
.is_strict = true, .is_contextual = true};
42+
4043
void PyCelActivation::DefinePythonBindings(py::module& m) {
4144
py::class_<PyCelActivation, std::shared_ptr<PyCelActivation>>(m,
4245
"Activation");
@@ -67,10 +70,10 @@ PyCelActivation::PyCelActivation(
6770
}
6871
cel::FunctionDescriptor func_descriptor(function->function_name(),
6972
function->is_member(), parameters,
70-
/*is_strict=*/true);
73+
kFunctionDescriptorOptions);
7174
activation_.InsertFunction(
7275
func_descriptor, std::make_unique<PyCelFunctionAdapter>(
73-
env, function->function_name(), function->impl()));
76+
function->function_name(), function->impl()));
7477
}
7578
};
7679

py_cel_env.cc

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,10 +172,7 @@ absl::StatusOr<PyCelExtension*> PyCelExtensionHandle::GetExtension(
172172
absl::Status status_py_cel_extension;
173173
try {
174174
pybind11::handle handle = pybind11::handle(py_extension_);
175-
PyCelPythonExtension* py_cel_extension =
176-
handle.cast<PyCelPythonExtension*>();
177-
status_py_cel_extension = py_cel_extension->SetEnv(env);
178-
return py_cel_extension;
175+
return handle.cast<PyCelPythonExtension*>();
179176
} catch (const pybind11::cast_error& e) {
180177
status_py_cel_extension = absl::InvalidArgumentError(e.what());
181178
}

py_cel_expression.cc

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <Python.h> // IWYU pragma: keep - Needed for PyObject
1818

1919
#include <cstdint>
20+
#include <cstring>
2021
#include <memory>
2122
#include <string>
2223
#include <utility>
@@ -38,6 +39,7 @@
3839
#include "compiler/compiler.h"
3940
#include "extensions/protobuf/runtime_adapter.h"
4041
#include "parser/parser_interface.h"
42+
#include "runtime/embedder_context.h"
4143
#include "runtime/runtime.h"
4244
#include "py_cel_activation.h"
4345
#include "py_cel_arena.h"
@@ -135,10 +137,17 @@ absl::StatusOr<PyCelValue> PyCelExpression::Eval(
135137
}
136138
std::shared_ptr<PyCelArena> arena = activation.GetArena();
137139
std::shared_ptr<PyCelEnv> env = activation.GetEnv();
140+
// uint8_t copiable_env[sizeof(std::shared_ptr<PyCelEnv>)];
141+
// memcpy(copiable_env, std::move(env), sizeof(std::shared_ptr<PyCelEnv>));
142+
// = (uint8_t*)(&env);
143+
cel::EmbedderContext embedder_context = cel::EmbedderContext::From(&env);
144+
cel::EvaluateOptions options;
145+
options.message_factory = env->GetMessageFactory();
146+
options.embedder_context = &embedder_context;
138147
CEL_PYTHON_ASSIGN_OR_RETURN(
139148
cel::Value result,
140-
cel_program_->Evaluate(arena->GetArena(), env->GetMessageFactory(),
141-
*activation.GetActivation()));
149+
cel_program_->Evaluate(arena->GetArena(), *activation.GetActivation(),
150+
std::move(options)));
142151
return PyCelValue(result, arena, std::move(env));
143152
}
144153

py_cel_function.cc

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "absl/strings/str_format.h"
2828
#include "absl/types/span.h"
2929
#include "common/value.h"
30+
#include "runtime/embedder_context.h"
3031
#include "runtime/function.h"
3132
#include "py_cel_env.h"
3233
#include "py_cel_type.h"
@@ -65,12 +66,9 @@ PyCelFunction::~PyCelFunction() {
6566
PyGILState_Release(gil_state);
6667
};
6768

68-
PyCelFunctionAdapter::PyCelFunctionAdapter(const std::shared_ptr<PyCelEnv>& env,
69-
std::string function_name,
69+
PyCelFunctionAdapter::PyCelFunctionAdapter(std::string function_name,
7070
PyObject* py_function)
71-
: env_(env),
72-
function_name_(std::move(function_name)),
73-
py_function_(py_function) {
71+
: function_name_(std::move(function_name)), py_function_(py_function) {
7472
Py_XINCREF(py_function_);
7573
}
7674

@@ -84,13 +82,18 @@ absl::StatusOr<cel::Value> PyCelFunctionAdapter::Invoke(
8482
absl::Span<const cel::Value> args,
8583
const cel::Function::InvokeContext& context) const {
8684
ABSL_CHECK(PyGILState_Check());
85+
ABSL_CHECK(context.embedder_context());
86+
87+
std::shared_ptr<PyCelEnv> env =
88+
*context.embedder_context()->Get<std::shared_ptr<PyCelEnv>*>();
89+
ABSL_CHECK(env);
8790

8891
PY_CEL_ASSIGN_OR_RETURN(auto py_arena,
8992
PyCelArena::FromProtoArena(context.arena()));
9093
PyObject* py_args = PyTuple_New(args.size());
9194
for (int i = 0; i < args.size(); ++i) {
9295
PyTuple_SetItem(py_args, i,
93-
CelValueToPyObject(args[i], env_, py_arena,
96+
CelValueToPyObject(args[i], env, py_arena,
9497
/*plain_value=*/true));
9598
}
9699
PyObject* result = PyObject_CallObject(py_function_, py_args);
@@ -105,7 +108,7 @@ absl::StatusOr<cel::Value> PyCelFunctionAdapter::Invoke(
105108
return absl::StrFormat("Python function '%s'",
106109
PyUnicode_AsUTF8(PyObject_Repr(py_function_)));
107110
},
108-
env_, context.arena());
111+
env, context.arena());
109112
};
110113

111114
} // namespace cel_python

py_cel_function.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,14 @@ class PyCelFunction {
6262
// function.
6363
class PyCelFunctionAdapter : public cel::Function {
6464
public:
65-
PyCelFunctionAdapter(const std::shared_ptr<PyCelEnv>& env,
66-
std::string function_name, PyObject* py_function);
65+
PyCelFunctionAdapter(std::string function_name, PyObject* py_function);
6766
~PyCelFunctionAdapter() override;
6867

6968
absl::StatusOr<cel::Value> Invoke(
7069
absl::Span<const cel::Value> args,
7170
const cel::Function::InvokeContext& context) const final;
7271

7372
private:
74-
std::shared_ptr<PyCelEnv> env_;
7573
std::string function_name_;
7674
PyObject* py_function_;
7775
};

py_cel_python_extension.cc

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ namespace cel_python {
4646

4747
namespace py = ::pybind11;
4848

49+
static const cel::FunctionDescriptorOptions kFunctionDescriptorOptions = {
50+
.is_strict = true, .is_contextual = true};
51+
4952
void PyCelPythonExtension::DefinePythonBindings(py::module_& m) {
5053
py::class_<PyCelExtension>(m, "CelExtensionBase")
5154
.def(py::init<std::string>(), py::arg("name"));
@@ -59,18 +62,6 @@ PyCelPythonExtension::PyCelPythonExtension(
5962
std::string name, std::vector<PyCelFunctionDecl> functions)
6063
: PyCelExtension(std::move(name)), functions_(std::move(functions)) {}
6164

62-
// TODO(b/462745713): pass the env to the Invoke method instead of storing it
63-
// as a member variable and remove this method.
64-
absl::Status PyCelPythonExtension::SetEnv(
65-
const std::shared_ptr<PyCelEnv>& env) {
66-
if (env_ != nullptr && env_ != env) {
67-
return absl::FailedPreconditionError(
68-
"PyCelExtension already has an environment");
69-
}
70-
env_ = env;
71-
return absl::OkStatus();
72-
}
73-
7465
absl::Status PyCelPythonExtension::ConfigureCompiler(
7566
cel::CompilerBuilder& compiler_builder,
7667
const google::protobuf::DescriptorPool& descriptor_pool) {
@@ -115,12 +106,11 @@ absl::Status PyCelPythonExtension::ConfigureRuntime(
115106
}
116107

117108
cel::FunctionDescriptor descriptor(function.name(), overload.is_member(),
118-
types,
119-
/*is_strict=*/true);
109+
types, kFunctionDescriptorOptions);
120110
if (overload.py_function()) {
121111
PY_CEL_RETURN_IF_ERROR(runtime_builder.function_registry().Register(
122112
descriptor, std::make_unique<PyCelFunctionAdapter>(
123-
env_, function.name(), overload.py_function())));
113+
function.name(), overload.py_function())));
124114
} else {
125115
PY_CEL_RETURN_IF_ERROR(
126116
runtime_builder.function_registry().RegisterLazyFunction(

py_cel_python_extension.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
#ifndef THIRD_PARTY_CEL_PYTHON_PY_CEL_PYTHON_EXTENSION_H_
1616
#define THIRD_PARTY_CEL_PYTHON_PY_CEL_PYTHON_EXTENSION_H_
1717

18-
#include <memory>
1918
#include <string>
2019
#include <vector>
2120

@@ -30,18 +29,12 @@
3029

3130
namespace cel_python {
3231

33-
class PyCelEnv;
34-
3532
class PyCelPythonExtension : public PyCelExtension {
3633
public:
3734
static void DefinePythonBindings(pybind11::module& m);
3835
PyCelPythonExtension(std::string name,
3936
std::vector<PyCelFunctionDecl> functions);
4037

41-
// TODO(b/462745713): pass the env to the Invoke method instead of storing it
42-
// as a member variable.
43-
absl::Status SetEnv(const std::shared_ptr<PyCelEnv>& env);
44-
4538
protected:
4639
absl::Status ConfigureCompiler(
4740
cel::CompilerBuilder& compiler_builder,
@@ -52,7 +45,6 @@ class PyCelPythonExtension : public PyCelExtension {
5245

5346
private:
5447
std::vector<PyCelFunctionDecl> functions_;
55-
std::shared_ptr<PyCelEnv> env_;
5648
};
5749

5850
} // namespace cel_python

0 commit comments

Comments
 (0)