Skip to content

Commit 9474fdf

Browse files
committed
Update to cel-interpreter 0.10
1 parent cee3654 commit 9474fdf

File tree

8 files changed

+318
-60
lines changed

8 files changed

+318
-60
lines changed

CHANGELOG.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
10+
### Changed
11+
- Updated `cel-interpreter` from 0.9.0 to 0.10.0
12+
13+
### Added
14+
- **Automatic Type Coercion**: Intelligent preprocessing of expressions to handle mixed int/float arithmetic
15+
- Expressions with float literals automatically convert integer literals to floats
16+
- Context variables containing floats trigger integer-to-float promotion for compatibility
17+
- Preserves array indexing with integers (e.g., `list[2]` remains as integer)
18+
- **Enhanced Error Handling**: Added panic handling with `std::panic::catch_unwind` for parser errors
19+
- Invalid expressions now return proper ValueError instead of crashing the Python process
20+
- Graceful handling of upstream parser panics from cel-interpreter
21+
22+
### Fixed
23+
- **Mixed-type arithmetic compatibility**: Expressions like `3.14 * 2`, `2 + 3.14`, `value * 2` (where value is float) now work as expected
24+
- **Parser panic handling**: Implemented `std::panic::catch_unwind` to gracefully handle upstream parser panics
25+
- Users get proper error messages instead of application crashes
26+
- Fixed deprecation warnings by updating to compatible PyO3 APIs
27+
28+
### Known Issues
29+
30+
- **Bytes Concatenation**: cel-interpreter 0.10.0 does not implement bytes concatenation with `+` operator
31+
- **CEL specification requires**: `b'hello' + b'world'` should work
32+
- **Current behavior**: Returns "Unsupported binary operator 'add'" error
33+
- **Workaround**: Use `bytes(string(part1) + string(part2))` for concatenation
34+
- **Status**: This is a missing feature in the cel-interpreter crate, not a design limitation
35+
36+
### Dependencies Updated
37+
- cel-interpreter: 0.9.0 → 0.10.0 (major version update with breaking changes)
38+
- log: 0.4.22 → 0.4.27
39+
- chrono: 0.4.38 → 0.4.41
40+
- PyO3 and related crates: Updated to resolve deprecation warnings
41+

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cel"
3-
version = "0.3.1"
3+
version = "0.4.0"
44
edition = "2021"
55

66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -10,7 +10,7 @@ crate-type = ["cdylib"]
1010

1111
[dependencies]
1212
pyo3 = { version = "0.22.6", features = ["chrono", "gil-refs", "py-clone"]}
13-
cel-interpreter = { version = "0.9.0", features = ["chrono", "json", "regex"] }
14-
log = "0.4.22"
13+
cel-interpreter = { version = "0.10.0", features = ["chrono", "json", "regex"] }
14+
log = "0.4.27"
1515
pyo3-log = "0.11.0"
16-
chrono = { version = "0.4.38", features = ["serde"] }
16+
chrono = { version = "0.4.41", features = ["serde"] }

pyproject.toml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11

22
[project]
33
name = "common-expression-language"
4+
description = "Python bindings for the Common Expression Language (CEL)"
5+
authors = [
6+
{name = "Brian Thorne", email = "[email protected]"}
7+
]
48
requires-python = ">=3.11"
59
classifiers = [
610
"Programming Language :: Rust",
@@ -11,8 +15,12 @@ dynamic = ["version"]
1115
dependencies = [
1216
]
1317

18+
[project.urls]
19+
Homepage = "https://github.com/hardbyte/python-common-expression-language"
20+
Repository = "https://github.com/hardbyte/python-common-expression-language"
21+
1422
[build-system]
15-
requires = ["maturin>=1.5,<2.0"]
23+
requires = ["maturin>=1.8,<2.0"]
1624
build-backend = "maturin"
1725

1826

@@ -21,7 +29,7 @@ features = ["pyo3/extension-module"]
2129

2230
[tool.uv]
2331
dev-dependencies = [
24-
"pytest>=8.3.3",
25-
"maturin>=1.7.4",
26-
"pip>=24.3.1",
32+
"pytest>=8.4.1",
33+
"maturin>=1.8.0",
34+
"pip>=25.0.0",
2735
]

src/context.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use cel_interpreter::objects::TryIntoValue;
22
use cel_interpreter::Value;
33
use pyo3::exceptions::PyValueError;
44
use pyo3::prelude::*;
5-
use pyo3::types::{PyDict, PyTuple};
5+
use pyo3::types::PyDict;
66
use std::collections::HashMap;
77

88
#[pyo3::pyclass]
@@ -14,7 +14,8 @@ pub struct Context {
1414
#[pyo3::pymethods]
1515
impl Context {
1616
#[new]
17-
pub fn new(variables: Option<&PyDict>, functions: Option<&PyDict>) -> PyResult<Self> {
17+
#[pyo3(signature = (variables=None, functions=None))]
18+
pub fn new(variables: Option<&Bound<'_, PyDict>>, functions: Option<&Bound<'_, PyDict>>) -> PyResult<Self> {
1819
let mut context = Context {
1920
variables: HashMap::new(),
2021
functions: HashMap::new(),
@@ -26,7 +27,7 @@ impl Context {
2627
let key = k
2728
.extract::<String>()
2829
.map_err(|_| PyValueError::new_err("Variable name must be strings"));
29-
key.map(|key| context.add_variable(key, v))??;
30+
key.map(|key| context.add_variable(key, &v))??;
3031
}
3132
};
3233

@@ -41,8 +42,8 @@ impl Context {
4142
self.functions.insert(name, function);
4243
}
4344

44-
pub fn add_variable(&mut self, name: String, value: &PyAny) -> PyResult<()> {
45-
let value = crate::RustyPyType(value).try_into_value().map_err(|e| {
45+
pub fn add_variable(&mut self, name: String, value: &Bound<'_, PyAny>) -> PyResult<()> {
46+
let value = crate::RustyPyType(&value).try_into_value().map_err(|e| {
4647
pyo3::exceptions::PyValueError::new_err(format!(
4748
"Failed to convert variable '{}': {}",
4849
name, e
@@ -52,7 +53,7 @@ impl Context {
5253
Ok(())
5354
}
5455

55-
pub fn update(&mut self, variables: &PyDict) -> PyResult<()> {
56+
pub fn update(&mut self, variables: &Bound<'_, PyDict>) -> PyResult<()> {
5657
for (key, value) in variables {
5758
// Attempt to extract the key as a String
5859
let key = key
@@ -65,7 +66,7 @@ impl Context {
6566
self.functions.insert(key, py_function);
6667
} else {
6768
// Value is a variable, add it to the variables hashmap
68-
let value = crate::RustyPyType(value)
69+
let value = crate::RustyPyType(&value)
6970
.try_into_value()
7071
.map_err(|e| PyValueError::new_err(e.to_string()))?;
7172

0 commit comments

Comments
 (0)