libpython-clj icon indicating copy to clipboard operation
libpython-clj copied to clipboard

py/with macro doesn't bind the return value of __enter__ method

Open lidorcg opened this issue 2 months ago • 0 comments

The py/with macro implementation doesn't correctly follow Python's with statement semantics. According to the Python documentation, the value bound in a with statement should be the return value of calling __enter__() on the context manager:

manager = (EXPRESSION)
enter = type(manager).__enter__
exit = type(manager).__exit__
value = enter(manager)  # This value should be bound to TARGET
hit_except = False

try:
    TARGET = value  # TARGET gets the return value of enter(manager)
    SUITE
...

Current Implementation

The current macro (with.clj#L45-L63) calls __enter__ but discards its return value:

(py-fn/call-attr ~varname "__enter__" nil)  ; Return value is ignored
(try
  (let [retval# (do ~@body)]
    ...

Expected Behavior

The bound variable should receive the return value of __enter__(), not the context manager itself:

(let [enter-result# (py-fn/call-attr ~varname "__enter__" nil)]
  (try
    (let [~varname enter-result#  ; Rebind to __enter__'s return value
          retval# (do ~@body)]
      ...

Why Current Tests Pass

The existing test in python_test.clj#L167 uses a WithObjClass where __enter__() returns None (implicitly), and the test methods are called on the original object. This masks the bug.

Real-World Example

A common Python pattern that fails with the current implementation:

with open('file.txt', 'r') as f:
    content = f.read()  # f should be the file object returned by __enter__

With the current macro, f would be bound to the unopened file path/manager rather than the file object returned by __enter__().

Next Steps

  1. Add test cases that verify this behavior (e.g., update WithObjClass.__enter__ to return a different object, or test with Python's built-in file context manager)
  2. Update the macro to correctly bind the return value of __enter__()

lidorcg avatar Nov 10 '25 16:11 lidorcg