Skip to content

fix: use python truthiness for compiled and/or Var operations#6546

Merged
adhami3310 merged 2 commits into
mainfrom
fix/python-truthiness-and-or-compilation
May 20, 2026
Merged

fix: use python truthiness for compiled and/or Var operations#6546
adhami3310 merged 2 commits into
mainfrom
fix/python-truthiness-and-or-compilation

Conversation

@adhami3310
Copy link
Copy Markdown
Member

Summary

The and_operation / or_operation Var operations compiled to JS && / ||, but JS and Python disagree on truthiness for container values:

  • Python: [] or TrueTrue (empty list is falsy)
  • JS: [] || true[] (empty array is truthy)

So a Reflex expression like Var([]) | True was producing [] || true in the frontend and resolving to [] instead of True. Same for {}, "", etc.

This PR routes the compiled output through new pyOr / pyAnd helpers that use the existing isTrue Python-truthiness check:

export const pyOr  = (a, b) => (isTrue(a) ? a : b());
export const pyAnd = (a, b) => (isTrue(a) ? b() : a);

The RHS is passed as a thunk (() => b) so short-circuit evaluation is preserved — b is not evaluated unless its branch is taken.

Compiled output change

Python Before After
a | b (a || b) pyOr(a, () => (b))
a & b (a && b) pyAnd(a, () => (b))

Repro

import reflex as rx


class State(rx.State):
    items: list[int] = []


def index():
    return rx.fragment(
        rx.text("or:  ", (State.items | True).to_string()),   # expected: "true",  was: "[]"
        rx.text("and: ", (State.items & True).to_string()),   # expected: "[]",    was: "true"
    )


app = rx.App()
app.add_page(index)

Before this change, the rendered values match JS truthiness ([] truthy) instead of Python truthiness ([] falsy). With this PR they match Python.

Test plan

  • uv run pytest tests/units — 4468 passed
  • uv run ruff check . and uv run ruff format --check . clean
  • Updated test_var.py assertions for the new compiled output
  • Manually verify the repro app in dev mode

JS `&&`/`||` use JS truthiness, where `[]` and `{}` are truthy. Python
treats them as falsy, so `Var([]) | true` was compiling to `[] || true`
and returning `[]` instead of `true`. Same issue for `Var({}) & x`,
`Var("") | y`, etc.

Compile `a | b` to `pyOr(a, () => b)` and `a & b` to `pyAnd(a, () => b)`,
backed by helpers that use `isTrue` for the truthiness check. RHS is
wrapped in a thunk so short-circuit semantics are preserved.
@adhami3310 adhami3310 requested a review from a team as a code owner May 20, 2026 20:04
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 20, 2026

Greptile Summary

This PR fixes a Python/JS truthiness mismatch for the compiled and/or Var operations. Previously a | b emitted (a || b), which treats [], {}, and "" as truthy in JS — the opposite of Python. The fix routes these through new pyOr/pyAnd JS helpers that delegate to the existing isTrue Python-truthiness check, with the RHS wrapped in a thunk to preserve short-circuit evaluation.

  • state.js: adds pyOr and pyAnd exports built on the pre-existing isTrue helper; both implementations are correct and consistent with Python's or/and semantics.
  • base.py: _and_operation/_or_operation now emit pyAnd(a, () => (b)) / pyOr(a, () => (b)) and inject the matching imports via VarData.
  • test_var.py: existing assertions are updated to the new compiled form, but no test exercises an empty-container operand (the actual motivating bug scenario).

Confidence Score: 4/5

Safe to merge; the helpers are tiny, clearly correct, and backed by the existing isTrue function.

The change is narrowly scoped and the logic is straightforward. The only gap is that tests verify the compiled output shape but don't exercise an empty-list or empty-dict operand, leaving the motivating scenario untested at the Python unit-test level.

tests/units/test_var.py could use an additional test case with empty-container Var operands to directly document and guard the fixed behaviour.

Important Files Changed

Filename Overview
packages/reflex-base/src/reflex_base/.templates/web/utils/state.js Adds pyOr and pyAnd JS helpers that delegate to the existing isTrue function; implementation is correct and short-circuit is preserved via thunks.
packages/reflex-base/src/reflex_base/vars/base.py Rewrites _and_operation/_or_operation to emit pyAnd/pyOr thunk calls with proper import injection; logic is correct and consistent with the var_operation_return pattern.
tests/units/test_var.py Updates compilation-output assertions to reflect new pyAnd/pyOr form; no new tests exercise the root cause (empty-container truthiness) at the JS level.

Reviews (1): Last reviewed commit: "fix: use python truthiness for compiled ..." | Re-trigger Greptile

Comment thread tests/units/test_var.py
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 20, 2026

Merging this PR will not alter performance

✅ 24 untouched benchmarks


Comparing fix/python-truthiness-and-or-compilation (5544019) with main (9bada16)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (6288dfe) during the generation of this report, so 9bada16 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@adhami3310 adhami3310 merged commit bf2deed into main May 20, 2026
90 of 92 checks passed
@adhami3310 adhami3310 deleted the fix/python-truthiness-and-or-compilation branch May 20, 2026 20:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants