clj-python / clj-python/libpython-clj

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

未關閉
#273 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

還沒有人認領這個 Issue。

主要語言
Clojure
星號
1.2k
分支
74
PR 合併指標
30 天內沒有已合併 PR

描述

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__()

貢獻指南

開啟貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

研究方向

從 src/libpython_clj2/python/with.clj#L45-L63 和 test/libpython_clj2/python_test.clj#L167 中現有的測試開始。使用 enter 回傳不同物件的內容管理器來新增覆蓋,然後驗證繫結的值就是該回傳值,並且現有的 with 行為仍然通過。

由索引模型根據 Issue 內容生成。

評估

技術堆疊
clojure, python
領域
tooling
Issue 類型
缺陷
難度
2/5
預估耗時
1-3 小時
活躍度
停滯
描述清晰度
描述清楚
新手友好度
58/100

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。