You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hy宏导入模块失效:with-cwd宏报NameError: os未定义

解决Hy语言with-cwd宏的NameError问题

问题背景

使用Hy 0.25.0编写pytest测试时,调用自定义的with-cwd宏触发NameError: name 'os' is not defined错误,但手动在测试文件中导入os后测试可正常运行。

测试文件代码

(import pytest [mark])
(import pathlib [Path])
(require oreo [with-cwd])
(defn [mark.with-cwd] test-with-cwd [cookies]
      (let [ cwd (.cwd Path) ]
           (with-cwd cookies (assert (= (.cwd Path) cookies)))
           (assert (= (.cwd Path) cwd))))

错误信息

Traceback (most recent call last):
  File "/home/shadowrylander/shadowrylander/sylveon/syvlorg/oreo/tests/test-with-cwd.hy", line 7, in test_with_cwd
    (with-cwd cookies (assert (= (.cwd Path) cookies)))
NameError: name 'os' is not defined

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/shadowrylander/shadowrylander/sylveon/syvlorg/oreo/tests/test-with-cwd.hy", line 7, in test_with_cwd
    (with-cwd cookies (assert (= (.cwd Path) cookies)))
NameError: name 'os' is not defined

cookies fixture定义

@pytest.fixture()
def cookies(request):
    from pathlib import Path
    return Path(request.config.rootdir).expanduser().resolve(strict = True) / "cookies"

原with-cwd宏实现

(eval-and-compile (import os hy))
(defmacro with-cwd [dir #* body]
          (setv cwd (hy.gensym))
          `(let [ ~cwd (.cwd Path) ]
                (try (.chdir os ~dir)
                     ~@body
                     (finally (.chdir os ~cwd)))))

尝试过的修改(仍报错)

(defmacro with-cwd [dir #* body]
          (setv cwd (hy.gensym)
                os (hy.gensym))
          `(let [ ~cwd (.cwd Path) ]
                (import os :as ~os)
                (try ((. ~os chdir) ~dir)
                     ~@body
                     (finally ((. ~os chdir) ~cwd)))))

解决方案

问题根源是:宏展开后的代码在调用者的命名空间中寻找os,但原宏仅在宏定义时导入os,并未将os的导入逻辑包含到展开后的代码中;修改后的宏虽尝试导入,但语法有误,且Path同样依赖调用者的导入。

正确的宏实现应确保展开后的代码自行导入所需依赖,避免依赖调用者的命名空间:

(eval-and-compile (import hy))
(defmacro with-cwd [dir #* body]
  (setv cwd (hy.gensym))
  `(do
     ;; 在展开后的代码中导入所需模块
     (import os)
     (import pathlib [Path])
     (let [~cwd (.cwd Path)]
       (try
         (.chdir os ~dir)
         ~@body
         (finally
           (.chdir os ~cwd))))))

如果希望复用调用者已导入的Path,至少要确保os在展开后的代码中被导入:

(eval-and-compile (import hy))
(defmacro with-cwd [dir #* body]
  (setv cwd (hy.gensym))
  `(do
     (import os)
     (let [~cwd (.cwd Path)]
       (try
         (.chdir os ~dir)
         ~@body
         (finally
           (.chdir os ~cwd))))))

修改后,宏展开时会自动在调用代码中插入os的导入语句,无需测试文件手动导入os即可正常运行。

内容的提问来源于stack exchange,提问作者syvlorg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 03:35:24