Skip to content

Commit 0e8ec95

Browse files
mani-dbtclaude
andcommitted
fix(jinja): support negative exponents in ** operator
Negative integer exponents (e.g. 10 ** -9) were failing with "unable to calculate 10 ** -9" because the I128 branch tried to convert the exponent to u32 for checked_pow, which fails for negative values. Fix by promoting to f64 arithmetic when the exponent is negative, matching Python/Jinja2 behavior. Adds unit tests covering the exact conversion_factor values used in dbt adapter macros. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ac8ca95 commit 0e8ec95

File tree

2 files changed

+32
-3
lines changed

2 files changed

+32
-3
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
kind: Fixes
2+
body: Fix `**` operator with negative exponents in Jinja (e.g. `10 ** -9`) to return float results, matching Python/Jinja2 behavior
3+
time: 2026-03-11T22:48:25.000000Z
4+
custom:
5+
author: manikantapachineelam
6+
issue: ""
7+
project: dbt-fusion

crates/dbt-jinja/minijinja/src/value/ops.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,15 @@ pub fn int_div(lhs: &Value, rhs: &Value) -> Result<Value, Error> {
412412
pub fn pow(lhs: &Value, rhs: &Value) -> Result<Value, Error> {
413413
match coerce(lhs, rhs, true) {
414414
Some(CoerceResult::I128(a, b)) => {
415-
match TryFrom::try_from(b).ok().and_then(|b| a.checked_pow(b)) {
416-
Some(val) => Ok(int_as_value(val)),
417-
None => Err(failed_op("**", lhs, rhs)),
415+
if b < 0 {
416+
// Negative exponents produce fractional results; promote to float
417+
// to match Python/Jinja2 behavior (e.g. 10 ** -9 == 1e-9).
418+
Ok((a as f64).powf(b as f64).into())
419+
} else {
420+
match TryFrom::try_from(b).ok().and_then(|b| a.checked_pow(b)) {
421+
Some(val) => Ok(int_as_value(val)),
422+
None => Err(failed_op("**", lhs, rhs)),
423+
}
418424
}
419425
}
420426
Some(CoerceResult::F64(a, b)) => Ok((a.powf(b)).into()),
@@ -720,4 +726,20 @@ mod tests {
720726
)
721727
);
722728
}
729+
730+
#[test]
731+
fn test_pow_negative_exponent() {
732+
// Negative integer exponents should produce float results to match
733+
// Python/Jinja2 behavior (e.g. used in dbt macros like conversion_factors).
734+
assert_eq!(pow(&Value::from(10i64), &Value::from(-9i64)).unwrap(), Value::from(1e-9_f64));
735+
assert_eq!(pow(&Value::from(10i64), &Value::from(-6i64)).unwrap(), Value::from(1e-6_f64));
736+
assert_eq!(pow(&Value::from(10i64), &Value::from(-3i64)).unwrap(), Value::from(1e-3_f64));
737+
738+
// Positive integer exponents should still return integers.
739+
assert_eq!(pow(&Value::from(10i64), &Value::from(2i64)).unwrap(), Value::from(100i64));
740+
assert_eq!(pow(&Value::from(2i64), &Value::from(8i64)).unwrap(), Value::from(256i64));
741+
742+
// Float exponents should continue to work.
743+
assert_eq!(pow(&Value::from(2.0f64), &Value::from(-1.0f64)).unwrap(), Value::from(0.5f64));
744+
}
723745
}

0 commit comments

Comments
 (0)